Prechádzať zdrojové kódy

Add custom theme overhaul

- Use 'config-overrides.js' with less loader to load ant.design's less files instead of the compiled css to override theme variables
- Change logo, favicon, and primary theme colours
- Add pageTitle() to App() to let components set page titles
- Move all notifications to bottomRight to avoid blocking action items on the UI
Kailash Nadh 6 rokov pred
rodič
commit
ac8c7ed93b

+ 30 - 0
frontend/my/config-overrides.js

@@ -0,0 +1,30 @@
+const {injectBabelPlugin} = require("react-app-rewired");
+const rewireLess = require("react-app-rewire-less");
+
+module.exports = function override(config, env) {
+  config = injectBabelPlugin(
+      [
+        "import", {
+          libraryName: "antd",
+          libraryDirectory: "es",
+          style: true
+        }
+      ],  // change importing css to less
+      config,
+  );
+  config = rewireLess.withLoaderOptions({
+    modifyVars: {
+      "@font-family":
+          '"IBM Plex Sans", "Helvetica Neueue", "Segoe UI", "sans-serif"',
+      "@font-size-base": "15px",
+      "@primary-color": "#7f2aff",
+      "@shadow-1-up": "0 -2px 3px @shadow-color",
+      "@shadow-1-down": "0 2px 3px @shadow-color",
+      "@shadow-1-left": "-2px 0 3px @shadow-color",
+      "@shadow-1-right": "2px 0 3px @shadow-color",
+      "@shadow-2": "0 2px 6px @shadow-color"
+    },
+    javascriptEnabled: true,
+  })(config, env);
+  return config;
+};

+ 13 - 2
frontend/my/package.json

@@ -7,20 +7,31 @@
     "axios": "^0.18.0",
     "dayjs": "^1.7.5",
     "react": "^16.4.1",
+    "react-app-rewire-less": "^2.1.3",
+    "react-app-rewired": "^1.6.2",
     "react-dom": "^16.4.1",
     "react-quill": "^1.3.1",
     "react-router": "^4.3.1",
     "react-router-dom": "^4.3.1",
     "react-scripts": "1.1.4"
   },
-  "scripts": {
+  "xxscripts": {
     "start": "react-scripts start",
     "build": "react-scripts build",
     "test": "react-scripts test --env=jsdom",
     "eject": "react-scripts eject"
   },
-  "theme": "./src/theme.js",
+  "scripts": {
+    "start": "react-app-rewired start",
+    "build": "react-app-rewired build",
+    "test": "react-app-rewired test --env=jsdom",
+    "eject": "react-scripts eject"
+  },
   "eslintConfig": {
     "extends": "react-app"
+  },
+  "devDependencies": {
+    "babel-plugin-import": "^1.11.0",
+    "less-plugin-npm-import": "^2.1.0"
   }
 }

BIN
frontend/my/public/favicon.ico


BIN
frontend/my/public/favicon.png


+ 3 - 2
frontend/my/public/index.html

@@ -5,9 +5,10 @@
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <meta name="theme-color" content="#000000">
     <script src="%PUBLIC_URL%/api/config.js" type="text/javascript"></script>
+    <link href="https://fonts.googleapis.com/css?family=IBM+Plex+Sans:400,600" rel="stylesheet">
     <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
-    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
-    <title>React App</title>
+    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.png">
+    <title>%PUBLIC_URL%</title>
   </head>
   <body>
     <noscript>

+ 8 - 1
frontend/my/src/App.js

@@ -112,12 +112,19 @@ class App extends React.PureComponent {
         }
     }
 
+
+    pageTitle = (title) => {
+        document.title = title
+    }
+
     render() {
         return (
             <BrowserRouter>
-                <Layout modelRequest={ this.modelRequest }
+                <Layout
+                    modelRequest={ this.modelRequest }
                     request={ this.request }
                     reqStates={ this.state.reqStates }
+                    pageTitle={ this.pageTitle }
                     config={ window.CONFIG }
                     data={ this.state.data } />
             </BrowserRouter>

+ 9 - 3
frontend/my/src/Campaign.js

@@ -214,7 +214,7 @@ class TheFormDef extends React.PureComponent {
             this.setState({ loading: true })
             if(!this.props.isSingle) {
                 this.props.modelRequest(cs.ModelCampaigns, cs.Routes.CreateCampaign, cs.MethodPost, values).then((resp) => {
-                    notification["success"]({ placement: "topRight",
+                    notification["success"]({ placement: cs.MsgPosition,
                         message: "Campaign created",
                         description: `"${values["name"]}" created` })
 
@@ -228,7 +228,7 @@ class TheFormDef extends React.PureComponent {
                 })
             } else {
                 this.props.modelRequest(cs.ModelCampaigns, cs.Routes.UpdateCampaign, cs.MethodPut, { ...values, id: this.props.record.id }).then((resp) => {
-                    notification["success"]({ placement: "topRight",
+                    notification["success"]({ placement: cs.MsgPosition,
                     message: "Campaign updated",
                     description: `"${values["name"]}" updated` })
                     this.setState({ loading: false })
@@ -259,7 +259,7 @@ class TheFormDef extends React.PureComponent {
             this.setState({ loading: true })
             this.props.request(cs.Routes.TestCampaign, cs.MethodPost, values).then((resp) => {
                 this.setState({ loading: false })
-                notification["success"]({ placement: "topRight",
+                notification["success"]({ placement: cs.MsgPosition,
                 message: "Test sent",
                 description: `Test messages sent` })
             }).catch(e => {
@@ -278,6 +278,12 @@ class TheFormDef extends React.PureComponent {
             subLists = record.lists.map((v) => { return v.id !== 0 ? v.id : null }).filter(v => v !== null)
         }
 
+        if(this.record) {
+            this.props.pageTitle(record.name + " / Campaigns")
+        } else {
+            this.props.pageTitle("New campaign")
+        }
+
         return (
             <div>
                 <Spin spinning={ this.state.loading }>

+ 1 - 0
frontend/my/src/Campaigns.js

@@ -248,6 +248,7 @@ class Campaigns extends React.PureComponent {
     }
 
     componentDidMount() {
+        this.props.pageTitle("Campaigns")
         dayjs.extend(relativeTime)
         this.fetchRecords()
     }

+ 4 - 2
frontend/my/src/Dashboard.js

@@ -1,7 +1,9 @@
 import React from 'react';
-import 'antd/dist/antd.css';
 
-class Dashboard extends React.Component {
+class Dashboard extends React.PureComponent {
+  componentDidMount = () => {
+    this.props.pageTitle("Dashboard")
+  }
   render() {
     return (
         <h1>Welcome</h1>

+ 1 - 0
frontend/my/src/Import.js

@@ -262,6 +262,7 @@ class Import extends React.PureComponent {
     }
 
     componentDidMount() {
+        this.props.pageTitle("Import subscribers")
         this.fetchimportState()
     }
     render() {

+ 3 - 2
frontend/my/src/Layout.js

@@ -3,7 +3,7 @@ import { Switch, Route } from "react-router-dom"
 import { Link } from "react-router-dom"
 import { Layout, Menu, Icon } from "antd"
 
-import "antd/dist/antd.css"
+// import "antd/dist/antd.css"
 import logo from "./static/listmonk.svg"
 
 // Views.
@@ -17,6 +17,7 @@ import Campaigns from "./Campaigns";
 import Campaign from "./Campaign";
 import Media from "./Media";
 
+
 const { Content, Footer, Sider } = Layout
 const SubMenu = Menu.SubMenu
 
@@ -30,7 +31,7 @@ class Base extends React.Component {
     onCollapse = (collapsed) => {
         this.setState({ collapsed })
     }
-    
+
     render() {
         return (
             <Layout style={{ minHeight: "100vh" }}>

+ 13 - 7
frontend/my/src/Lists.js

@@ -23,7 +23,7 @@ class CreateFormDef extends React.PureComponent {
             if (this.props.formType === cs.FormCreate) {
                 // Create a new list.
                 this.props.modelRequest(cs.ModelLists, cs.Routes.CreateList, cs.MethodPost, values).then(() => {
-                    notification["success"]({ placement: "topRight", message: "List created", description: `"${values["name"]}" created` })
+                    notification["success"]({ placement: cs.MsgPosition, message: "List created", description: `"${values["name"]}" created` })
                     this.props.fetchRecords()
                     this.props.onClose()
                     this.setState({ modalWaiting: false })
@@ -34,7 +34,7 @@ class CreateFormDef extends React.PureComponent {
             } else {
                 // Edit a list.
                 this.props.modelRequest(cs.ModelLists, cs.Routes.UpdateList, cs.MethodPut, { ...values, id: this.props.record.id }).then(() => {
-                    notification["success"]({ placement: "topRight", message: "List modified", description: `"${values["name"]}" modified` })
+                    notification["success"]({ placement: cs.MsgPosition, message: "List modified", description: `"${values["name"]}" modified` })
                     this.props.fetchRecords()
                     this.props.onClose()
                     this.setState({ modalWaiting: false })
@@ -111,7 +111,7 @@ class Lists extends React.PureComponent {
             title: "Name",
             dataIndex: "name",
             sorter: true,
-            width: "50%",
+            width: "40%",
             render: (text, record) => {
                 const out = [];
                 out.push(
@@ -130,7 +130,7 @@ class Lists extends React.PureComponent {
         {
             title: "Type",
             dataIndex: "type",
-            width: "5%",
+            width: "10%",
             render: (type, _) => {
                 let color = type === "private" ? "orange" : "green"
                 return <Tag color={color}>{type}</Tag>
@@ -139,8 +139,13 @@ class Lists extends React.PureComponent {
         {
             title: "Subscribers",
             dataIndex: "subscriber_count",
-            width: "10%",
-            align: "center"
+            width: "15%",
+            align: "center",
+            render: (text, record) => {
+                return(
+                    <div className="name" key={`name-${record.id}`}><Link to={ `/subscribers/lists/${record.id}` }>{ text }</Link></div>
+                )
+            }
         },
         {
             title: "Created",
@@ -175,6 +180,7 @@ class Lists extends React.PureComponent {
     }
 
     componentDidMount() {
+        this.props.pageTitle("Lists")
         this.fetchRecords()
     }
 
@@ -185,7 +191,7 @@ class Lists extends React.PureComponent {
     deleteRecord = (record) => {
         this.props.modelRequest(cs.ModelLists, cs.Routes.DeleteList, cs.MethodDelete, { id: record.id })
             .then(() => {
-                notification["success"]({ placement: "topRight", message: "List deleted", description: `"${record.name}" deleted` })
+                notification["success"]({ placement: cs.MsgPosition, message: "List deleted", description: `"${record.name}" deleted` })
                 
                 // Reload the table.
                 this.fetchRecords()

+ 2 - 1
frontend/my/src/Media.js

@@ -8,6 +8,7 @@ class TheFormDef extends React.PureComponent {
     }
 
     componentDidMount() {
+        this.props.pageTitle("Media")
         this.fetchRecords()
     }
 
@@ -18,7 +19,7 @@ class TheFormDef extends React.PureComponent {
     handleDeleteRecord = (record) => {
         this.props.modelRequest(cs.ModelMedia, cs.Routes.DeleteMedia, cs.MethodDelete, { id: record.id })
             .then(() => {
-                notification["success"]({ placement: "topRight", message: "Image deleted", description: `"${record.filename}" deleted` })
+                notification["success"]({ placement: cs.MsgPosition, message: "Image deleted", description: `"${record.filename}" deleted` })
 
                 // Reload the table.
                 this.fetchRecords()

+ 21 - 2
frontend/my/src/Subscribers.js

@@ -1,4 +1,5 @@
 import React from "react"
+import { Link } from "react-router-dom"
 import { Row, Col, Modal, Form, Input, Select, Button, Table, Icon, Tooltip, Tag, Popconfirm, Spin, notification } from "antd"
 
 import Utils from "./utils"
@@ -233,9 +234,21 @@ class Subscribers extends React.PureComponent {
             sorter: true,
             width: "25%",
             render: (text, record) => {
-                return (
-                    <a role="button" onClick={() => this.handleShowEditForm(record)}>{text}</a>
+                
+                const out = [];
+                out.push(
+                    <div key={`sub-email-${ record.id }`} className="sub-name">
+                        <a role="button" onClick={() => { this.handleShowEditForm(record)}}>{text}</a>
+                    </div>
                 )
+                
+                if(record.lists.length > 0) {
+                    for (let i = 0; i < record.lists.length; i++) {
+                        out.push(<Tag className="list" key={`sub-${ record.id }-list-${ record.lists[i].id }`}><Link to={ `/subscribers/lists/${ record.lists[i].id }` }>{ record.lists[i].name }</Link></Tag>)
+                    }
+                }
+
+                return out
             }
         },
         {
@@ -406,6 +419,12 @@ class Subscribers extends React.PureComponent {
             ...this.state.queryParams
         }
 
+        if(this.state.queryParams.list) {
+            this.props.pageTitle(this.state.queryParams.list.name + " / Subscribers")
+        } else {
+            this.props.pageTitle("Subscribers")
+        }
+
         return (
             <section className="content">
                 <header className="header">

+ 5 - 4
frontend/my/src/Templates.js

@@ -25,7 +25,7 @@ class CreateFormDef extends React.PureComponent {
             if (this.props.formType === cs.FormCreate) {
                 // Create a new list.
                 this.props.modelRequest(cs.ModelTemplates, cs.Routes.CreateTemplate, cs.MethodPost, values).then(() => {
-                    notification["success"]({ placement: "topRight", message: "Template added", description: `"${values["name"]}" added` })
+                    notification["success"]({ placement: cs.MsgPosition, message: "Template added", description: `"${values["name"]}" added` })
                     this.props.fetchRecords()
                     this.props.onClose()
                     this.setState({ modalWaiting: false })
@@ -36,7 +36,7 @@ class CreateFormDef extends React.PureComponent {
             } else {
                 // Edit a list.
                 this.props.modelRequest(cs.ModelTemplates, cs.Routes.UpdateTemplate, cs.MethodPut, { ...values, id: this.props.record.id }).then(() => {
-                    notification["success"]({ placement: "topRight", message: "Template updated", description: `"${values["name"]}" modified` })
+                    notification["success"]({ placement: cs.MsgPosition, message: "Template updated", description: `"${values["name"]}" modified` })
                     this.props.fetchRecords()
                     this.props.onClose()
                     this.setState({ modalWaiting: false })
@@ -196,6 +196,7 @@ class Templates extends React.PureComponent {
     }
 
     componentDidMount() {
+        this.props.pageTitle("Templates")
         this.fetchRecords()
     }
 
@@ -206,7 +207,7 @@ class Templates extends React.PureComponent {
     handleDeleteRecord = (record) => {
         this.props.modelRequest(cs.ModelTemplates, cs.Routes.DeleteTemplate, cs.MethodDelete, { id: record.id })
             .then(() => {
-                notification["success"]({ placement: "topRight", message: "Template deleted", description: `"${record.name}" deleted` })
+                notification["success"]({ placement: cs.MsgPosition, message: "Template deleted", description: `"${record.name}" deleted` })
 
                 // Reload the table.
                 this.fetchRecords()
@@ -218,7 +219,7 @@ class Templates extends React.PureComponent {
     handleSetDefault = (record) => {
         this.props.modelRequest(cs.ModelTemplates, cs.Routes.SetDefaultTemplate, cs.MethodPut, { id: record.id })
             .then(() => {
-                notification["success"]({ placement: "topRight", message: "Template updated", description: `"${record.name}" set as default` })
+                notification["success"]({ placement: cs.MsgPosition, message: "Template updated", description: `"${record.name}" set as default` })
                 
                 // Reload the table.
                 this.fetchRecords()

+ 1 - 0
frontend/my/src/constants.js

@@ -27,6 +27,7 @@ export const FormEdit = "edit"
 export const MsgSuccess = "success"
 export const MsgWarning = "warning"
 export const MsgError = "error"
+export const MsgPosition = "bottomRight"
 
 // Model specific.
 export const CampaignStatusColors = {

+ 9 - 2
frontend/my/src/index.css

@@ -4,6 +4,10 @@
   transition: none !important;
 }
 
+body {
+  font-weight: 400;
+}
+
 header.header {
   margin-bottom: 30px;
 }
@@ -54,7 +58,7 @@ body {
   }
   .logo img {
     width: auto;
-    height: 22px;
+    height: 28px;
   }
 
 .ant-layout-sider.ant-layout-sider-collapsed .logo a {
@@ -75,10 +79,13 @@ td.actions {
   text-align: right;
 }
 
+td .ant-tag {
+  margin-top: 5px;
+}
+
 /* Templates */
 .wysiwyg {
   padding: 30px;
-  color: red;
 }
 
 /* Subscribers */

+ 55 - 65
frontend/my/src/static/listmonk.svg

@@ -9,9 +9,9 @@
    xmlns="http://www.w3.org/2000/svg"
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="41.535763mm"
-   height="8.3702965mm"
-   viewBox="0 0 41.535763 8.3702965"
+   width="45.041653mm"
+   height="9.8558731mm"
+   viewBox="0 0 45.041653 9.8558733"
    version="1.1"
    id="svg8"
    sodipodi:docname="listmonk.svg"
@@ -25,9 +25,9 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="1"
-     inkscape:cx="41.789813"
-     inkscape:cy="42.352202"
+     inkscape:zoom="4"
+     inkscape:cx="71.96648"
+     inkscape:cy="2.639304"
      inkscape:document-units="mm"
      inkscape:current-layer="layer1"
      showgrid="false"
@@ -56,66 +56,56 @@
      inkscape:label="Layer 1"
      inkscape:groupmode="layer"
      id="layer1"
-     transform="translate(-88.728827,-97.568868)">
-    <g
-       aria-label="listmonk"
-       style="font-style:normal;font-weight:normal;font-size:8.44721699px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21118042"
-       id="text817">
-      <path
-         d="m 98.79092,104.90855 h 0.76025 v -6.3861 h -0.76025 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path944" />
-      <path
-         d="m 100.82023,104.90855 h 0.76025 v -4.00398 h -0.76025 z m -0.17739,-5.440011 c 0,0.3041 0.25342,0.557521 0.55752,0.557521 0.3041,0 0.55751,-0.253421 0.55751,-0.557521 0,-0.3041 -0.25341,-0.557517 -0.55751,-0.557517 -0.3041,0 -0.55752,0.253417 -0.55752,0.557517 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path946" />
-      <path
-         d="m 105.51042,101.46208 c -0.28721,-0.47304 -0.83628,-0.65888 -1.36845,-0.65888 -0.7518,0 -1.5205,0.39702 -1.5205,1.23329 0,0.7687 0.57441,0.97988 1.22485,1.14038 0.32944,0.076 0.96298,0.16049 0.96298,0.61664 0,0.34634 -0.42236,0.50684 -0.81093,0.50684 -0.43926,0 -0.72646,-0.22808 -0.97143,-0.47305 l -0.57441,0.47305 c 0.39701,0.54062 0.88695,0.70956 1.54584,0.70956 0.79403,0 1.62186,-0.35478 1.62186,-1.25863 0,-0.7518 -0.50683,-1.00522 -1.16571,-1.16572 -0.33789,-0.076 -1.02212,-0.1436 -1.02212,-0.62509 0,-0.28721 0.31255,-0.4477 0.66733,-0.4477 0.38013,0 0.64199,0.17739 0.81938,0.39701 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path948" />
-      <path
-         d="m 108.68116,100.90457 h -1.08969 v -1.123484 h -0.76025 v 1.123484 h -0.87851 v 0.65888 h 0.87851 v 2.08646 c 0,0.64199 0.0169,1.36 1.19106,1.36 0.15205,0 0.50683,-0.0338 0.68422,-0.13515 v -0.69267 c -0.15205,0.0929 -0.36323,0.11826 -0.54062,0.11826 -0.57441,0 -0.57441,-0.47305 -0.57441,-0.92075 v -1.81615 h 1.08969 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path950" />
-      <path
-         d="m 109.65378,104.90855 h 0.76025 v -2.07802 c 0,-0.90385 0.48994,-1.31776 1.039,-1.31776 0.73491,0 0.84473,0.54062 0.84473,1.30087 v 2.09491 h 0.76025 v -2.18783 c 0,-0.70957 0.2872,-1.20795 1.02211,-1.20795 0.73491,0 0.86162,0.55751 0.86162,1.16571 v 2.23007 h 0.76024 v -2.33144 c 0,-0.8954 -0.2872,-1.77391 -1.52049,-1.77391 -0.4815,0 -1.00522,0.25342 -1.26709,0.74335 -0.25341,-0.48993 -0.65888,-0.74335 -1.25018,-0.74335 -0.71802,0 -1.20796,0.48994 -1.28398,0.72646 h -0.0169 v -0.62509 h -0.70956 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path952" />
-      <path
-         d="m 117.46376,102.90656 c 0,-0.81094 0.50683,-1.39379 1.31776,-1.39379 0.81094,0 1.31777,0.58285 1.31777,1.39379 0,0.81093 -0.50683,1.39379 -1.31777,1.39379 -0.81093,0 -1.31776,-0.58286 -1.31776,-1.39379 z m -0.81094,0 c 0,1.16571 0.93765,2.10335 2.1287,2.10335 1.19106,0 2.1287,-0.93764 2.1287,-2.10335 0,-1.16572 -0.93764,-2.10336 -2.1287,-2.10336 -1.19105,0 -2.1287,0.93764 -2.1287,2.10336 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path954" />
-      <path
-         d="m 121.86265,104.90855 h 0.76024 v -2.06112 c 0,-0.9292 0.4815,-1.33466 1.11504,-1.33466 0.48149,0 0.9123,0.27875 0.9123,1.03056 v 2.36522 h 0.76025 v -2.5764 c 0,-1.06435 -0.67578,-1.52895 -1.45292,-1.52895 -0.61665,0 -1.12348,0.29565 -1.31777,0.71801 h -0.0169 v -0.61664 h -0.76024 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path956" />
-      <path
-         d="m 126.56471,104.90855 h 0.76025 v -2.07802 l 1.85839,2.07802 h 1.08124 l -2.02733,-2.17939 1.86683,-1.81615 h -1.0559 l -1.72323,1.73168 v -4.12224 h -0.76025 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path958" />
-    </g>
-    <circle
-       style="fill:none;fill-opacity:1;stroke:#7f2aff;stroke-width:1.05596864;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path874"
-       cx="92.280685"
-       cy="102.38731"
-       r="3.0238743" />
+     transform="translate(-12.438455,-21.535559)">
     <path
-       style="fill:#7f2aff;fill-opacity:1;stroke:none;stroke-width:1.15863311;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 92.280686,99.698318 a 3.0238741,3.6404374 0 0 0 -3.023758,3.640282 3.0238741,3.6404374 0 0 0 0.0697,0.75725 3.0238741,3.6404374 0 0 1 2.954053,-2.87212 3.0238741,3.6404374 0 0 1 2.954051,2.88305 3.0238741,3.6404374 0 0 0 0.0697,-0.76818 3.0238741,3.6404374 0 0 0 -3.023756,-3.640282 z"
-       id="circle878"
-       inkscape:connector-curvature="0" />
+       style="fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:2.11094689;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 16.660914,21.535559 a 4.2220837,4.2220837 0 0 0 -4.222459,4.222437 4.2220837,4.2220837 0 0 0 0.490699,1.968681 c 0.649637,-1.386097 2.059696,-2.343758 3.73176,-2.343758 1.672279,0 3.082188,0.958029 3.731731,2.344413 a 4.2220837,4.2220837 0 0 0 0.490039,-1.969336 4.2220837,4.2220837 0 0 0 -4.22177,-4.222437 z"
+       id="circle920"
+       inkscape:connector-curvature="0"
+       inkscape:export-filename="/home/kailash/Site/listmonk/static/logo.png"
+       inkscape:export-xdpi="96"
+       inkscape:export-ydpi="96" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot935"
+       style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
+       transform="matrix(0.27888442,0,0,0.27888442,92.852428,101.67857)"><flowRegion
+         id="flowRegion937"><rect
+           id="rect939"
+           width="338"
+           height="181"
+           x="-374"
+           y="-425.36423" /></flowRegion><flowPara
+         id="flowPara941" /></flowRoot>    <text
+       id="text874-8"
+       y="30.29347"
+       x="23.133614"
+       style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:8.70788765px;line-height:1.25;font-family:'IBM Plex Sans';-inkscape-font-specification:'IBM Plex Sans, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.0459737"
+       xml:space="preserve"
+       inkscape:export-filename="/home/kailash/Site/listmonk/static/logo.png"
+       inkscape:export-xdpi="96"
+       inkscape:export-ydpi="96"><tspan
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.70788765px;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.0459737"
+         y="30.29347"
+         x="23.133614"
+         id="tspan872-0"
+         sodipodi:role="line">listmonk</tspan></text>
+    <circle
+       r="3.1873188"
+       cy="27.647591"
+       cx="16.66629"
+       id="circle876-1"
+       style="fill:none;fill-opacity:1;stroke:#7f2aff;stroke-width:1.11304522;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       inkscape:export-filename="/home/kailash/Site/listmonk/static/logo.png"
+       inkscape:export-xdpi="96"
+       inkscape:export-ydpi="96" />
     <path
-       style="fill:#7f2aff;fill-opacity:1;stroke:none;stroke-width:1.05596864;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path873"
-       sodipodi:type="arc"
-       sodipodi:cx="92.280685"
-       sodipodi:cy="-99.267464"
-       sodipodi:rx="1.6985958"
-       sodipodi:ry="1.6985958"
-       sodipodi:start="0"
-       sodipodi:end="3.1415927"
-       d="m 93.979281,-99.267464 a 1.6985958,1.6985958 0 0 1 -0.849298,1.471027 1.6985958,1.6985958 0 0 1 -1.698596,0 1.6985958,1.6985958 0 0 1 -0.849297,-1.471027 l 1.698595,0 z"
-       transform="scale(1,-1)" />
+       inkscape:connector-curvature="0"
+       id="path878-0"
+       d="m 16.666291,24.813242 a 3.1873187,3.8372081 0 0 0 -3.187196,3.837044 3.1873187,3.8372081 0 0 0 0.07347,0.79818 3.1873187,3.8372081 0 0 1 3.113724,-3.027362 3.1873187,3.8372081 0 0 1 3.113721,3.038883 3.1873187,3.8372081 0 0 0 0.07347,-0.809701 3.1873187,3.8372081 0 0 0 -3.187196,-3.837044 z"
+       style="fill:#7f2aff;fill-opacity:1;stroke:none;stroke-width:1.22125876;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       inkscape:export-filename="/home/kailash/Site/listmonk/static/logo.png"
+       inkscape:export-xdpi="96"
+       inkscape:export-ydpi="96" />
   </g>
 </svg>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 538 - 19
frontend/my/yarn.lock


+ 0 - 121
public/static/logo.svg

@@ -1,121 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="41.535763mm"
-   height="8.3702965mm"
-   viewBox="0 0 41.535763 8.3702965"
-   version="1.1"
-   id="svg8"
-   sodipodi:docname="listmonk.svg"
-   inkscape:version="0.92.3 (2405546, 2018-03-11)">
-  <defs
-     id="defs2" />
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="1"
-     inkscape:cx="41.789813"
-     inkscape:cy="42.352202"
-     inkscape:document-units="mm"
-     inkscape:current-layer="layer1"
-     showgrid="false"
-     inkscape:window-width="1853"
-     inkscape:window-height="1025"
-     inkscape:window-x="67"
-     inkscape:window-y="27"
-     inkscape:window-maximized="1"
-     fit-margin-top="0"
-     fit-margin-left="0"
-     fit-margin-right="0"
-     fit-margin-bottom="0" />
-  <metadata
-     id="metadata5">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title></dc:title>
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer"
-     id="layer1"
-     transform="translate(-88.728827,-97.568868)">
-    <g
-       aria-label="listmonk"
-       style="font-style:normal;font-weight:normal;font-size:8.44721699px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21118042"
-       id="text817">
-      <path
-         d="m 98.79092,104.90855 h 0.76025 v -6.3861 h -0.76025 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path944" />
-      <path
-         d="m 100.82023,104.90855 h 0.76025 v -4.00398 h -0.76025 z m -0.17739,-5.440011 c 0,0.3041 0.25342,0.557521 0.55752,0.557521 0.3041,0 0.55751,-0.253421 0.55751,-0.557521 0,-0.3041 -0.25341,-0.557517 -0.55751,-0.557517 -0.3041,0 -0.55752,0.253417 -0.55752,0.557517 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path946" />
-      <path
-         d="m 105.51042,101.46208 c -0.28721,-0.47304 -0.83628,-0.65888 -1.36845,-0.65888 -0.7518,0 -1.5205,0.39702 -1.5205,1.23329 0,0.7687 0.57441,0.97988 1.22485,1.14038 0.32944,0.076 0.96298,0.16049 0.96298,0.61664 0,0.34634 -0.42236,0.50684 -0.81093,0.50684 -0.43926,0 -0.72646,-0.22808 -0.97143,-0.47305 l -0.57441,0.47305 c 0.39701,0.54062 0.88695,0.70956 1.54584,0.70956 0.79403,0 1.62186,-0.35478 1.62186,-1.25863 0,-0.7518 -0.50683,-1.00522 -1.16571,-1.16572 -0.33789,-0.076 -1.02212,-0.1436 -1.02212,-0.62509 0,-0.28721 0.31255,-0.4477 0.66733,-0.4477 0.38013,0 0.64199,0.17739 0.81938,0.39701 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path948" />
-      <path
-         d="m 108.68116,100.90457 h -1.08969 v -1.123484 h -0.76025 v 1.123484 h -0.87851 v 0.65888 h 0.87851 v 2.08646 c 0,0.64199 0.0169,1.36 1.19106,1.36 0.15205,0 0.50683,-0.0338 0.68422,-0.13515 v -0.69267 c -0.15205,0.0929 -0.36323,0.11826 -0.54062,0.11826 -0.57441,0 -0.57441,-0.47305 -0.57441,-0.92075 v -1.81615 h 1.08969 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path950" />
-      <path
-         d="m 109.65378,104.90855 h 0.76025 v -2.07802 c 0,-0.90385 0.48994,-1.31776 1.039,-1.31776 0.73491,0 0.84473,0.54062 0.84473,1.30087 v 2.09491 h 0.76025 v -2.18783 c 0,-0.70957 0.2872,-1.20795 1.02211,-1.20795 0.73491,0 0.86162,0.55751 0.86162,1.16571 v 2.23007 h 0.76024 v -2.33144 c 0,-0.8954 -0.2872,-1.77391 -1.52049,-1.77391 -0.4815,0 -1.00522,0.25342 -1.26709,0.74335 -0.25341,-0.48993 -0.65888,-0.74335 -1.25018,-0.74335 -0.71802,0 -1.20796,0.48994 -1.28398,0.72646 h -0.0169 v -0.62509 h -0.70956 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path952" />
-      <path
-         d="m 117.46376,102.90656 c 0,-0.81094 0.50683,-1.39379 1.31776,-1.39379 0.81094,0 1.31777,0.58285 1.31777,1.39379 0,0.81093 -0.50683,1.39379 -1.31777,1.39379 -0.81093,0 -1.31776,-0.58286 -1.31776,-1.39379 z m -0.81094,0 c 0,1.16571 0.93765,2.10335 2.1287,2.10335 1.19106,0 2.1287,-0.93764 2.1287,-2.10335 0,-1.16572 -0.93764,-2.10336 -2.1287,-2.10336 -1.19105,0 -2.1287,0.93764 -2.1287,2.10336 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path954" />
-      <path
-         d="m 121.86265,104.90855 h 0.76024 v -2.06112 c 0,-0.9292 0.4815,-1.33466 1.11504,-1.33466 0.48149,0 0.9123,0.27875 0.9123,1.03056 v 2.36522 h 0.76025 v -2.5764 c 0,-1.06435 -0.67578,-1.52895 -1.45292,-1.52895 -0.61665,0 -1.12348,0.29565 -1.31777,0.71801 h -0.0169 v -0.61664 h -0.76024 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path956" />
-      <path
-         d="m 126.56471,104.90855 h 0.76025 v -2.07802 l 1.85839,2.07802 h 1.08124 l -2.02733,-2.17939 1.86683,-1.81615 h -1.0559 l -1.72323,1.73168 v -4.12224 h -0.76025 z"
-         style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Avenir LT Std';-inkscape-font-specification:'Avenir LT Std Semi-Bold';fill:#000000;stroke-width:0.21118042"
-         id="path958" />
-    </g>
-    <circle
-       style="fill:none;fill-opacity:1;stroke:#7f2aff;stroke-width:1.05596864;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path874"
-       cx="92.280685"
-       cy="102.38731"
-       r="3.0238743" />
-    <path
-       style="fill:#7f2aff;fill-opacity:1;stroke:none;stroke-width:1.15863311;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 92.280686,99.698318 a 3.0238741,3.6404374 0 0 0 -3.023758,3.640282 3.0238741,3.6404374 0 0 0 0.0697,0.75725 3.0238741,3.6404374 0 0 1 2.954053,-2.87212 3.0238741,3.6404374 0 0 1 2.954051,2.88305 3.0238741,3.6404374 0 0 0 0.0697,-0.76818 3.0238741,3.6404374 0 0 0 -3.023756,-3.640282 z"
-       id="circle878"
-       inkscape:connector-curvature="0" />
-    <path
-       style="fill:#7f2aff;fill-opacity:1;stroke:none;stroke-width:1.05596864;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="path873"
-       sodipodi:type="arc"
-       sodipodi:cx="92.280685"
-       sodipodi:cy="-99.267464"
-       sodipodi:rx="1.6985958"
-       sodipodi:ry="1.6985958"
-       sodipodi:start="0"
-       sodipodi:end="3.1415927"
-       d="m 93.979281,-99.267464 a 1.6985958,1.6985958 0 0 1 -0.849298,1.471027 1.6985958,1.6985958 0 0 1 -1.698596,0 1.6985958,1.6985958 0 0 1 -0.849297,-1.471027 l 1.698595,0 z"
-       transform="scale(1,-1)" />
-  </g>
-</svg>

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov