Skip to content

Commit 3767209

Browse files
authored
Add features to landing website (#881)
* docs: add info about pro version * feat(backend): return main website url * feat(frontend): display Ryot pro link in footer * fix(ts-utils): remove hoisted variables * fix(frontend): no-wrap for title * build(backend): upgrade deps * fix(backend): correct logic for exercise interacted * feat(frontend): display user ID in profile page * fix(frontend): use new variable names * fix(frontend): do not include stuff * feat(*): return creator as nested object * feat(backend): change name of subquery * feat(backend): return collaborators for collections * refactor(backend): use aliased entity where suitable * fix(backend): remove admin account guard * chore(backend): remove useless variable * feat(backend): do not ignore issuer id * feat(backend): empty array when no collaborators * fix(frontend): display num collaborators * fix(frontend): do not display if no items * chore(frontend): change order of stuff to display * refactor(backend): use aliased table where necessary * chore(backend): add comment * feat(backend): add log statement after registering user * feat(landing): add basic features page * ci: do not draft an update release * docs: make installation clearer * feat(landing): add features to footer * chore(backend): add separators * feat(landing): add basic heading to features page * feat(backend): do not unwrap background jobs completely * feat(landing): more layout changes * feat(landing): add info about pricing * feat(landing): add recommendations heading * feat(landing): add spacing * feat(landing): add info about recommendations pro feature * feat(frontend): display edit btn only for collection creator * feat(landing): change image for recomendations * feat(landing): make it mobile friendly * fix(landing): add padding to footer * fix(landing): some padding changes * feat(landing): add collection collaboration feature * fix(landing): reverse in mobile * feat(landing): change layout of features * feat(landing): some more changes * feat(landing): change image for collection collaboration * feat(landing): mention trial period * feat(landing): update links to new page * feat(landing): add link to contact section * feat: add refs to features * ci: correct endpoint for health * refactor(frontend): extract into component * fix(frontend): truncate text * ci: change order of response calling * refactor(frontend): extract modal to outside component * feat(frontend): close modal on submit * refactor(backend): extract season name into constant * feat(backend): do not create calendar events for specials * feat(database): delete all invalid calendar events * feat(landing): change image for collections * feat(landing): add info about new collection features * feat(landing): guide pricing tiers to discord * feat(frontend): change ryot pro colors * feat(frontend): autosize collection * feat(landing): more collection names * feat(landing): better wording of features * chore(backend): update order
1 parent 1331ec3 commit 3767209

File tree

14 files changed

+167
-56
lines changed

14 files changed

+167
-56
lines changed

apps/backend/src/miscellaneous/resolver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1414,9 +1414,9 @@ impl MiscellaneousService {
14141414
author_name: AUTHOR.to_owned(),
14151415
timezone: self.timezone.to_string(),
14161416
oidc_enabled: self.oidc_client.is_some(),
1417-
website_url: "https://ryot.io".to_owned(),
14181417
page_limit: self.config.frontend.page_size,
14191418
docs_link: "https://docs.ryot.io".to_owned(),
1419+
website_url: "https://ryot.io/features".to_owned(),
14201420
local_auth_disabled: self.config.users.disable_local_auth,
14211421
token_valid_for_days: self.config.users.token_valid_for_days,
14221422
repository_link: "https://github.com/ignisda/ryot".to_owned(),

apps/frontend/app/components/common.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
} from "@mantine/core";
2121
import { DateInput, DateTimePicker } from "@mantine/dates";
2222
import { useDebouncedState, useDidUpdate } from "@mantine/hooks";
23-
import { Form } from "@remix-run/react";
23+
import { Form, useNavigation } from "@remix-run/react";
2424
import {
2525
CollectionExtraInformationLot,
2626
type EntityLot,
@@ -30,7 +30,7 @@ import {
3030
} from "@ryot/generated/graphql/backend/graphql";
3131
import { formatDateToNaiveDate, groupBy, snakeCase } from "@ryot/ts-utils";
3232
import { IconExternalLink, IconSearch, IconX } from "@tabler/icons-react";
33-
import { Fragment, type ReactNode, useRef } from "react";
33+
import { Fragment, type ReactNode, useEffect, useRef } from "react";
3434
import { useState } from "react";
3535
import { match } from "ts-pattern";
3636
import { withoutHost } from "ufo";
@@ -148,6 +148,7 @@ export const AddEntityToCollectionModal = (props: {
148148
entityLot: EntityLot;
149149
collections: Array<Collection>;
150150
}) => {
151+
const transition = useNavigation();
151152
const selectData = Object.entries(
152153
groupBy(props.collections, (c) =>
153154
c.creator.id === props.userId ? "You" : c.creator.name,
@@ -162,6 +163,11 @@ export const AddEntityToCollectionModal = (props: {
162163
const [selectedCollection, setSelectedCollection] =
163164
useState<Collection | null>(null);
164165
const [ownedOn, setOwnedOn] = useState<Date | null>();
166+
useEffect(() => {
167+
if (transition.state !== "submitting") {
168+
props.onClose();
169+
}
170+
}, [transition.state]);
165171

166172
return (
167173
<Modal
@@ -170,11 +176,7 @@ export const AddEntityToCollectionModal = (props: {
170176
withCloseButton={false}
171177
centered
172178
>
173-
<Form
174-
action="/actions?intent=addEntityToCollection"
175-
method="post"
176-
onSubmit={() => props.onClose()}
177-
>
179+
<Form action="/actions?intent=addEntityToCollection" method="post">
178180
<input readOnly hidden name="entityId" value={props.entityId} />
179181
<input readOnly hidden name="entityLot" value={props.entityLot} />
180182
<HiddenLocationInput />

apps/frontend/app/routes/_dashboard.collections.list.tsx

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -233,40 +233,9 @@ export default function Page() {
233233
onClose={createOrUpdateModalClose}
234234
withCloseButton={false}
235235
centered
236+
size="lg"
236237
>
237-
<Box component={Form} method="post" action="?intent=createOrUpdate">
238-
<Stack>
239-
<Title order={3}>
240-
{toUpdateCollection ? "Update" : "Create"} collection
241-
</Title>
242-
<TextInput
243-
label="Name"
244-
required
245-
name="name"
246-
defaultValue={
247-
toUpdateCollection ? toUpdateCollection.name : undefined
248-
}
249-
readOnly={toUpdateCollection?.isDefault}
250-
/>
251-
<Textarea
252-
label="Description"
253-
name="description"
254-
defaultValue={
255-
toUpdateCollection?.description
256-
? toUpdateCollection.description
257-
: undefined
258-
}
259-
/>
260-
<Button
261-
variant="outline"
262-
type="submit"
263-
name={toUpdateCollection ? "updateId" : undefined}
264-
value={toUpdateCollection ? toUpdateCollection.id : undefined}
265-
>
266-
{toUpdateCollection ? "Update" : "Create"}
267-
</Button>
268-
</Stack>
269-
</Box>
238+
<CreateOrUpdateModal toUpdateCollection={toUpdateCollection} />
270239
</Modal>
271240
</>
272241
);
@@ -364,3 +333,46 @@ const DisplayCollection = (props: {
364333
</Flex>
365334
);
366335
};
336+
337+
const CreateOrUpdateModal = (props: {
338+
toUpdateCollection: UpdateCollectionInput | undefined;
339+
}) => {
340+
return (
341+
<Box component={Form} method="post" action="?intent=createOrUpdate">
342+
<Stack>
343+
<Title order={3}>
344+
{props.toUpdateCollection ? "Update" : "Create"} collection
345+
</Title>
346+
<TextInput
347+
label="Name"
348+
required
349+
name="name"
350+
defaultValue={
351+
props.toUpdateCollection ? props.toUpdateCollection.name : undefined
352+
}
353+
readOnly={props.toUpdateCollection?.isDefault}
354+
/>
355+
<Textarea
356+
label="Description"
357+
name="description"
358+
defaultValue={
359+
props.toUpdateCollection?.description
360+
? props.toUpdateCollection.description
361+
: undefined
362+
}
363+
autosize
364+
/>
365+
<Button
366+
variant="outline"
367+
type="submit"
368+
name={props.toUpdateCollection ? "updateId" : undefined}
369+
value={
370+
props.toUpdateCollection ? props.toUpdateCollection.id : undefined
371+
}
372+
>
373+
{props.toUpdateCollection ? "Update" : "Create"}
374+
</Button>
375+
</Stack>
376+
</Box>
377+
);
378+
};

apps/frontend/app/routes/_dashboard.settings.notifications.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ const DisplayNotification = (props: {
320320
<Paper p="xs" withBorder>
321321
<Flex align="center" justify="space-between">
322322
<Box w="80%">
323-
<Text size="sm" fw="bold">
323+
<Text size="sm" fw="bold" truncate>
324324
{props.notification.description}
325325
</Text>
326326
<Text size="xs">

apps/frontend/app/routes/_dashboard.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -484,19 +484,19 @@ const Footer = () => {
484484
return (
485485
<Stack>
486486
<Flex gap={80} justify="center">
487-
{/* {!loaderData.coreDetails.isPro ? (
487+
{!loaderData.coreDetails.isPro ? (
488488
<Anchor href={loaderData.coreDetails.websiteUrl} target="_blank">
489-
<Text c="lime" fw="bold">
489+
<Text c="red" fw="bold">
490490
Ryot Pro
491491
</Text>
492492
</Anchor>
493-
) : null} */}
493+
) : null}
494494
<Anchor href="https://diptesh.me" target="_blank">
495495
<Text c="indigo" fw="bold">
496496
{loaderData.coreDetails.authorName}
497497
</Text>
498498
</Anchor>
499-
<Text c="pink" fw="bold" visibleFrom="md">
499+
<Text c="grape" fw="bold" visibleFrom="md">
500500
{loaderData.coreDetails.timezone}
501501
</Text>
502502
<Anchor href={loaderData.coreDetails.repositoryLink} target="_blank">
Loading
Loading

apps/landing/src/config/landing.interface.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export interface Brand {
6161

6262
export interface PricingData {
6363
title: string;
64+
discord: string;
6465
tiers: Tier[];
6566
}
6667

@@ -72,6 +73,7 @@ export interface Tier {
7273

7374
export interface Price {
7475
amount: string;
76+
trial?: number;
7577
period?: string;
7678
}
7779

apps/landing/src/data/landing.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"logoPath": "https://raw.githubusercontent.com/IgnisDa/ryot/main/libs/assets/icon-512x512.png",
2828
"links": [
2929
{ "label": "Prices", "href": "/#pricing-section" },
30+
{ "label": "Features", "href": "/features" },
3031
{ "label": "Contact", "href": "/#contact-section" },
3132
{ "label": "Documentation", "href": "https://docs.ryot.io" },
3233
{ "label": "Terms of Service", "href": "/terms" }
@@ -43,20 +44,23 @@
4344
},
4445
"pricingData": {
4546
"title": "Ryot Pro Pricing",
47+
"discord": "https://discord.gg/D9XTg2a7R8",
4648
"tiers": [
4749
{
4850
"title": "Monthly",
4951
"price": {
5052
"amount": "$5",
51-
"period": "/month"
53+
"period": "/month",
54+
"trial": 7
5255
},
5356
"cta": "Get started"
5457
},
5558
{
5659
"title": "Yearly",
5760
"price": {
5861
"amount": "$49",
59-
"period": "/year"
62+
"period": "/year",
63+
"trial": 14
6064
},
6165
"cta": "Get started"
6266
},
@@ -74,6 +78,7 @@
7478
"description": "A self hosted platform for tracking various facets of your life - media, fitness and much more!",
7579
"links": [
7680
{ "label": "Prices", "href": "/#pricing-section" },
81+
{ "label": "Features", "href": "/features" },
7782
{ "label": "Contact", "href": "/#contact-section" },
7883
{ "label": "Documentation", "href": "https://docs.ryot.io" },
7984
{ "label": "Terms of Service", "href": "/terms" }

apps/landing/src/pages/features.astro

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
---
2+
import Layout from "@/layouts/Layout.astro";
3+
import Footer from "@/sections/Footer.astro";
4+
import Header from "@/sections/Header.astro";
5+
import { getLandingData } from "@/services/data.service";
6+
7+
const data = await getLandingData();
8+
---
9+
10+
<Layout meta={data.meta}>
11+
<Header data={data.headerData} />
12+
<main>
13+
<div class="py-56 flex flex-col gap-y-20 md:gap-y-32">
14+
<div class="px-3 text-center">
15+
<h1 class="text-5xl md:text-6xl font-bold">Features</h1>
16+
<p class="text-slate-500 mt-8 md:mt-16 md:text-xl">
17+
An overview of all the features Ryot Pro provides.
18+
</p>
19+
</div>
20+
<div class="px-4 md:px-60 gap-y-4 flex flex-col">
21+
<h2 class="text-2xl font-semibold md:text-4xl md:font-normal">
22+
Recommendations
23+
</h2>
24+
<div
25+
class="gap-y-5 flex flex-col-reverse items-center justify-between md:gap-x-10 md:flex-row"
26+
>
27+
<p class="md:text-xl">
28+
A new section called "Recommendations" is added to the Dashboard
29+
where you can view personalized suggestions based on your recent
30+
media consumption. They are refreshed every hour.
31+
</p>
32+
<img
33+
src="images/features/recommendations.png"
34+
class="lg:w-[600px] border rounded-lg shadow-lg"
35+
/>
36+
</div>
37+
</div>
38+
<div class="px-4 md:px-60 gap-y-4 flex flex-col">
39+
<h2 class="text-2xl font-semibold md:text-4xl md:font-normal">
40+
Supercharged Collections
41+
</h2>
42+
<div
43+
class="gap-y-5 flex flex-col items-center justify-between md:gap-x-10 md:flex-row"
44+
>
45+
<img
46+
src="images/features/add-to-others-collection.png"
47+
class="lg:w-[600px] border rounded-lg shadow-lg"
48+
/>
49+
<ul class="list-disc list-inside">
50+
<li class="md:text-xl">
51+
Create information templates for your collections. These templates
52+
will be used when you add media to your collection. You can see an
53+
example of this on the community edition with the "Owned" and
54+
"Reminders" collection.
55+
</li>
56+
<li class="md:text-xl">
57+
Add collaborators to your collections. This feature is useful when
58+
you want to share your collection with your friends or family.
59+
They can also add or remove media from it.
60+
</li>
61+
</ul>
62+
</div>
63+
</div>
64+
<div class="px-4 text-center">
65+
<p class="md:text-xl">
66+
Have a feature request?
67+
<a href="/#contact-section" class="underline text-blue-500"
68+
>Contact us</a
69+
> to let us know.
70+
</p>
71+
</div>
72+
</div>
73+
<Footer data={data.footerData} />
74+
</main>
75+
</Layout>

0 commit comments

Comments
 (0)