diff --git a/components.d.ts b/components.d.ts index 224b2a4..59117c3 100644 --- a/components.d.ts +++ b/components.d.ts @@ -7,9 +7,11 @@ export {} /* prettier-ignore */ declare module 'vue' { export interface GlobalComponents { + ChipTag: typeof import('./src/components/ChipTag.vue')['default'] + DiscordLogo: typeof import('./src/components/DiscordLogo.vue')['default'] FlowinityLogo: typeof import('./src/components/FlowinityLogo.vue')['default'] + FlowinityWordmark: typeof import('./src/components/FlowinityWordmark.vue')['default'] Header: typeof import('./src/components/Header.vue')['default'] - HelloWorld: typeof import('./src/components/HelloWorld.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] } diff --git a/graphql.schema.json b/graphql.schema.json index d8a08c5..a30bc7c 100644 --- a/graphql.schema.json +++ b/graphql.schema.json @@ -33,13 +33,9 @@ "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } + "kind": "SCALAR", + "name": "Date", + "ofType": null }, "isDeprecated": false, "deprecationReason": null @@ -49,13 +45,9 @@ "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null }, "isDeprecated": false, "deprecationReason": null @@ -65,13 +57,21 @@ "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "BannerType", - "ofType": null - } + "kind": "ENUM", + "name": "BannerType", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "content", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null }, "isDeprecated": false, "deprecationReason": null @@ -85,7 +85,7 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "String", + "name": "Date", "ofType": null } }, @@ -108,6 +108,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "flowinityUser", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "FlowinityUser", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "flowinityUserId", "description": null, @@ -140,6 +152,22 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "image", + "description": "Resolvable URL to an image", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "title", "description": null, @@ -165,7 +193,7 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "String", + "name": "Date", "ofType": null } }, @@ -261,6 +289,73 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "SCALAR", + "name": "Date", + "description": null, + "isOneOf": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "FlowinityUser", + "description": null, + "isOneOf": null, + "fields": [ + { + "name": "avatar", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "username", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "SCALAR", "name": "Int", @@ -278,6 +373,35 @@ "description": null, "isOneOf": null, "fields": [ + { + "name": "announcement", + "description": null, + "args": [ + { + "name": "id", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "OBJECT", + "name": "Announcement", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "announcements", "description": null, diff --git a/package.json b/package.json index 28e3344..ba05ab2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "troplo-website-next", - "version": "0.0.0", + "version": "2.0.1", "scripts": { "dev": "vite", "build": "vue-tsc --noEmit && vite build", @@ -13,11 +13,15 @@ "@graphql-codegen/cli": "^5.0.2", "@graphql-codegen/introspection": "^4.0.3", "@mdi/font": "^7.4.47", + "@types/markdown-it": "^14.1.2", "@vue/apollo-composable": "^4.2.1", "core-js": "^3.37.1", + "dayjs": "^1.11.13", "graphql": "^16.9.0", "graphql-tag": "^2.12.6", + "markdown-it": "^14.1.0", "pinia": "^2.2.2", + "prettier": "^3.3.3", "roboto-fontface": "*", "vue": "^3.4.31", "vuetify": "^3.6.11" diff --git a/public/images/crystal-icon.svg b/public/images/crystal-icon.svg new file mode 100644 index 0000000..121f8ba --- /dev/null +++ b/public/images/crystal-icon.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/public/images/flowinity-update-comms.png b/public/images/flowinity-update-comms.png new file mode 100644 index 0000000..c078a44 Binary files /dev/null and b/public/images/flowinity-update-comms.png differ diff --git a/src/App.vue b/src/App.vue index 7924f37..5e6e181 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,51 +1,6 @@ diff --git a/src/components/ChipTag.vue b/src/components/ChipTag.vue new file mode 100644 index 0000000..9abcd32 --- /dev/null +++ b/src/components/ChipTag.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/src/components/DiscordLogo.vue b/src/components/DiscordLogo.vue new file mode 100644 index 0000000..60f74e6 --- /dev/null +++ b/src/components/DiscordLogo.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/src/components/FlowinityLogo.vue b/src/components/FlowinityLogo.vue index 582914b..633f399 100644 --- a/src/components/FlowinityLogo.vue +++ b/src/components/FlowinityLogo.vue @@ -4,7 +4,7 @@ fill-rule="evenodd" clip-rule="evenodd" d="M418.455 0.303628C368.601 3.53963 317.099 15.4736 274.671 33.6216C247.274 45.3406 230.542 54.3696 204.955 71.2386C176.877 89.7506 157.205 105.979 130.432 132.715C92.391 170.705 65.015 208.32 43.462 252.215C24.648 290.532 12.494 328.601 5.50901 371.098C0.525014 401.415 -0.0489904 409.979 0.00300957 453.215C0.0460096 488.587 0.307011 495.159 2.26401 510.012C12.064 584.424 36.235 647.831 76.868 705.715C88.227 721.897 108.825 746.978 121.86 760.5V760.5C123.716 762.425 126.973 761.118 126.983 758.444L127.455 635.5L127.933 510.88C127.948 507.16 128.87 503.498 130.62 500.215V500.215C134.346 493.224 140.794 486.918 147.366 483.836C152.023 481.652 154.372 481.215 161.455 481.215C168.538 481.215 170.887 481.652 175.544 483.836C182.369 487.037 188.65 493.382 192.253 500.715V500.715C194.031 504.333 194.959 508.311 194.965 512.342L195.22 665.376L195.464 811.774C195.477 819.73 199.528 827.136 206.22 831.44V831.44C219.113 839.731 233.998 848.715 234.844 848.715C235.18 848.715 235.455 724.137 235.455 571.875C235.455 301.89 235.503 294.849 237.38 287.507C243.152 264.94 260.408 246.135 281.881 239.012C289.036 236.639 291.492 236.334 303.455 236.334C315.418 236.334 317.874 236.639 325.029 239.012C346.502 246.135 363.758 264.94 369.53 287.507C371.409 294.855 371.455 302.194 371.455 595.356V893.375C371.455 894.718 372.392 895.879 373.705 896.164V896.164C376.489 896.767 387.479 898.218 401.955 899.893C414.535 901.348 479.439 901.702 491.685 900.382V900.382C496.084 899.907 499.42 896.197 499.426 891.773L499.685 708.382L499.943 525.666C499.951 520.069 500.875 514.512 502.679 509.215V509.215C506.467 498.094 511.754 489.557 519.98 481.282C527.75 473.464 535.038 468.745 545.213 464.94C553.437 461.865 572.642 460.71 582.746 462.683C605.287 467.084 624.838 484.756 633.131 508.225V508.225C635 513.513 635.963 519.08 635.979 524.689L636.455 689.875L636.913 848.991C636.932 855.678 643.978 860.012 649.955 857.013V857.013C664.911 849.51 682.159 839.593 695.901 830.595V830.595C701.863 826.692 705.455 820.046 705.455 812.92V583.211C705.455 413.319 705.777 340.339 706.546 336.18C708.763 324.185 716.558 313.757 727.23 308.507C733.573 305.387 734.5 305.215 744.939 305.219C755.049 305.222 758.649 305.954 763.5 308.507C774.055 314.061 779.116 322.479 781.905 333.185C783.281 338.467 783.455 362.492 783.455 547.048C783.455 741.465 783.564 754.871 785.131 753.587C786.054 752.833 791.159 746.998 796.477 740.621C856.831 668.25 888.647 594.484 899.156 502.556C901.658 480.679 901.662 423.739 899.164 401.215C893.347 348.771 882.256 306.938 862.869 264.33C824.083 179.088 751.55 100.867 667.955 54.1346C618.093 26.2596 566.07 9.88263 502.955 2.19063C490.626 0.687629 432.526 -0.609372 418.455 0.303628Z" - :fill="fill ? fill : theme.current.value.dark ? 'white' : 'black'" + :fill="theme.current.value.dark ? 'white' : 'black'" /> @@ -12,12 +12,6 @@ diff --git a/src/components/FlowinityWordmark.vue b/src/components/FlowinityWordmark.vue new file mode 100644 index 0000000..5bb5c30 --- /dev/null +++ b/src/components/FlowinityWordmark.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/src/components/Header.vue b/src/components/Header.vue index 91a3916..6f996c3 100644 --- a/src/components/Header.vue +++ b/src/components/Header.vue @@ -1,42 +1,69 @@ diff --git a/src/gql/gql.ts b/src/gql/gql.ts index 18d0de5..2b2aa65 100644 --- a/src/gql/gql.ts +++ b/src/gql/gql.ts @@ -13,7 +13,8 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { - "\n query Announcements($input: AnnouncementsInput!) {\n announcements(input: $input) {\n id\n title\n description\n createdAt\n updatedAt\n banner\n bannerText\n bannerExpiry\n bannerType\n flowinityUserId\n }\n }\n": types.AnnouncementsDocument, + "\n query Announcement($announcementId: String!) {\n announcement(id: $announcementId) {\n id\n title\n description\n content\n createdAt\n updatedAt\n bannerExpiry\n image\n flowinityUser {\n username\n avatar\n }\n }\n }\n": types.AnnouncementDocument, + "\n query Announcements($input: AnnouncementsInput!) {\n announcements(input: $input) {\n id\n title\n description\n createdAt\n updatedAt\n image\n banner\n bannerText\n bannerExpiry\n bannerType\n flowinityUserId\n }\n }\n": types.AnnouncementsDocument, "\n query StatusPage {\n status {\n name\n status\n }\n }\n": types.StatusPageDocument, }; @@ -34,7 +35,11 @@ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query Announcements($input: AnnouncementsInput!) {\n announcements(input: $input) {\n id\n title\n description\n createdAt\n updatedAt\n banner\n bannerText\n bannerExpiry\n bannerType\n flowinityUserId\n }\n }\n"): (typeof documents)["\n query Announcements($input: AnnouncementsInput!) {\n announcements(input: $input) {\n id\n title\n description\n createdAt\n updatedAt\n banner\n bannerText\n bannerExpiry\n bannerType\n flowinityUserId\n }\n }\n"]; +export function graphql(source: "\n query Announcement($announcementId: String!) {\n announcement(id: $announcementId) {\n id\n title\n description\n content\n createdAt\n updatedAt\n bannerExpiry\n image\n flowinityUser {\n username\n avatar\n }\n }\n }\n"): (typeof documents)["\n query Announcement($announcementId: String!) {\n announcement(id: $announcementId) {\n id\n title\n description\n content\n createdAt\n updatedAt\n bannerExpiry\n image\n flowinityUser {\n username\n avatar\n }\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n query Announcements($input: AnnouncementsInput!) {\n announcements(input: $input) {\n id\n title\n description\n createdAt\n updatedAt\n image\n banner\n bannerText\n bannerExpiry\n bannerType\n flowinityUserId\n }\n }\n"): (typeof documents)["\n query Announcements($input: AnnouncementsInput!) {\n announcements(input: $input) {\n id\n title\n description\n createdAt\n updatedAt\n image\n banner\n bannerText\n bannerExpiry\n bannerType\n flowinityUserId\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/src/gql/graphql.ts b/src/gql/graphql.ts index 976572c..13d6a40 100644 --- a/src/gql/graphql.ts +++ b/src/gql/graphql.ts @@ -14,20 +14,25 @@ export type Scalars = { Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } + Date: { input: any; output: any; } }; export type Announcement = { __typename?: 'Announcement'; banner: Scalars['String']['output']; - bannerExpiry: Scalars['String']['output']; - bannerText: Scalars['String']['output']; - bannerType: BannerType; - createdAt: Scalars['String']['output']; + bannerExpiry?: Maybe; + bannerText?: Maybe; + bannerType?: Maybe; + content?: Maybe; + createdAt: Scalars['Date']['output']; description: Scalars['String']['output']; + flowinityUser?: Maybe; flowinityUserId: Scalars['Int']['output']; id: Scalars['String']['output']; + /** Resolvable URL to an image */ + image: Scalars['String']['output']; title: Scalars['String']['output']; - updatedAt: Scalars['String']['output']; + updatedAt: Scalars['Date']['output']; }; export type AnnouncementsInput = { @@ -44,14 +49,27 @@ export enum BannerType { Warning = 'warning' } +export type FlowinityUser = { + __typename?: 'FlowinityUser'; + avatar?: Maybe; + id: Scalars['Int']['output']; + username: Scalars['String']['output']; +}; + export type Query = { __typename?: 'Query'; + announcement?: Maybe; announcements: Array; information: Scalars['String']['output']; status: Array; }; +export type QueryAnnouncementArgs = { + id: Scalars['String']['input']; +}; + + export type QueryAnnouncementsArgs = { input: AnnouncementsInput; }; @@ -70,12 +88,19 @@ export type StatusMonitor = { status: Status; }; +export type AnnouncementQueryVariables = Exact<{ + announcementId: Scalars['String']['input']; +}>; + + +export type AnnouncementQuery = { __typename?: 'Query', announcement?: { __typename?: 'Announcement', id: string, title: string, description: string, content?: string | null, createdAt: any, updatedAt: any, bannerExpiry?: any | null, image: string, flowinityUser?: { __typename?: 'FlowinityUser', username: string, avatar?: string | null } | null } | null }; + export type AnnouncementsQueryVariables = Exact<{ input: AnnouncementsInput; }>; -export type AnnouncementsQuery = { __typename?: 'Query', announcements: Array<{ __typename?: 'Announcement', id: string, title: string, description: string, createdAt: string, updatedAt: string, banner: string, bannerText: string, bannerExpiry: string, bannerType: BannerType, flowinityUserId: number }> }; +export type AnnouncementsQuery = { __typename?: 'Query', announcements: Array<{ __typename?: 'Announcement', id: string, title: string, description: string, createdAt: any, updatedAt: any, image: string, banner: string, bannerText?: string | null, bannerExpiry?: any | null, bannerType?: BannerType | null, flowinityUserId: number }> }; export type StatusPageQueryVariables = Exact<{ [key: string]: never; }>; @@ -83,5 +108,6 @@ export type StatusPageQueryVariables = Exact<{ [key: string]: never; }>; export type StatusPageQuery = { __typename?: 'Query', status: Array<{ __typename?: 'StatusMonitor', name: string, status: Status }> }; -export const AnnouncementsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Announcements"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AnnouncementsInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"announcements"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"banner"}},{"kind":"Field","name":{"kind":"Name","value":"bannerText"}},{"kind":"Field","name":{"kind":"Name","value":"bannerExpiry"}},{"kind":"Field","name":{"kind":"Name","value":"bannerType"}},{"kind":"Field","name":{"kind":"Name","value":"flowinityUserId"}}]}}]}}]} as unknown as DocumentNode; +export const AnnouncementDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Announcement"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"announcementId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"announcement"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"announcementId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"bannerExpiry"}},{"kind":"Field","name":{"kind":"Name","value":"image"}},{"kind":"Field","name":{"kind":"Name","value":"flowinityUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}}]}}]}}]}}]} as unknown as DocumentNode; +export const AnnouncementsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Announcements"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AnnouncementsInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"announcements"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"image"}},{"kind":"Field","name":{"kind":"Name","value":"banner"}},{"kind":"Field","name":{"kind":"Name","value":"bannerText"}},{"kind":"Field","name":{"kind":"Name","value":"bannerExpiry"}},{"kind":"Field","name":{"kind":"Name","value":"bannerType"}},{"kind":"Field","name":{"kind":"Name","value":"flowinityUserId"}}]}}]}}]} as unknown as DocumentNode; export const StatusPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"StatusPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/src/graphql/announcements/announcement.query.ts b/src/graphql/announcements/announcement.query.ts new file mode 100644 index 0000000..2890cc6 --- /dev/null +++ b/src/graphql/announcements/announcement.query.ts @@ -0,0 +1,20 @@ +import gql from "graphql-tag" + +export const AnnouncementQuery = gql` + query Announcement($announcementId: String!) { + announcement(id: $announcementId) { + id + title + description + content + createdAt + updatedAt + bannerExpiry + image + flowinityUser { + username + avatar + } + } + } +` diff --git a/src/graphql/announcements/announcements.query.ts b/src/graphql/announcements/announcements.query.ts index 64ab3f1..1dbd900 100644 --- a/src/graphql/announcements/announcements.query.ts +++ b/src/graphql/announcements/announcements.query.ts @@ -8,6 +8,7 @@ export const AnnouncementsQuery = gql` description createdAt updatedAt + image banner bannerText bannerExpiry diff --git a/src/lib/dayjs.ts b/src/lib/dayjs.ts new file mode 100644 index 0000000..4b35823 --- /dev/null +++ b/src/lib/dayjs.ts @@ -0,0 +1,13 @@ +/** + * plugins/dayjs.ts + */ + +import dayjs from "dayjs"; +import advancedFormat from "dayjs/plugin/advancedFormat"; +import relativeTime from "dayjs/plugin/relativeTime"; +import customParseFormat from "dayjs/plugin/customParseFormat"; + +dayjs.extend(advancedFormat); +dayjs.extend(relativeTime); +dayjs.extend(customParseFormat); +export default dayjs; diff --git a/src/lib/mdAnnouncements.ts b/src/lib/mdAnnouncements.ts new file mode 100644 index 0000000..302c1fb --- /dev/null +++ b/src/lib/mdAnnouncements.ts @@ -0,0 +1,16 @@ +import MarkdownIt from "markdown-it" + +const md = new MarkdownIt({ + html: true, + linkify: true, + typographer: false, + breaks: true, + quotes: "“”‘’", + langPrefix: "language-", + xhtmlOut: true +}) + +const mdNoHtml = new MarkdownIt("commonmark", {}) + +export default md +export { mdNoHtml } diff --git a/src/pages/404.vue b/src/pages/[...path].vue similarity index 77% rename from src/pages/404.vue rename to src/pages/[...path].vue index 79b6e5c..97ec7a9 100644 --- a/src/pages/404.vue +++ b/src/pages/[...path].vue @@ -5,7 +5,9 @@

Not Found.

This route does not exist.

- Go Home + Go Home
diff --git a/src/pages/contact.vue b/src/pages/contact.vue index 64f0bcc..0c3378c 100644 --- a/src/pages/contact.vue +++ b/src/pages/contact.vue @@ -13,8 +13,18 @@ >
- {{ contact.icon }} - + {{ contact.icon }} + + {{ contact.title }} @@ -31,6 +41,7 @@ diff --git a/src/pages/news/index.vue b/src/pages/news/index.vue new file mode 100644 index 0000000..d2ec53c --- /dev/null +++ b/src/pages/news/index.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/src/plugins/apollo.ts b/src/plugins/apollo.ts index a5f1a29..2838c76 100644 --- a/src/plugins/apollo.ts +++ b/src/plugins/apollo.ts @@ -2,7 +2,7 @@ import { ApolloClient, createHttpLink, InMemoryCache } from "@apollo/client" const httpLink = createHttpLink({ // You should use an absolute URL here - uri: "/graphql" + uri: import.meta.env.DEV ? "/graphql" : "https://api.troplo.com/graphql" }) // Cache implementation diff --git a/src/stores/announcements.store.ts b/src/stores/announcements.store.ts index eebeee1..0a5b2a5 100644 --- a/src/stores/announcements.store.ts +++ b/src/stores/announcements.store.ts @@ -1,26 +1,47 @@ import { defineStore } from "pinia" -import { Announcement, AnnouncementsDocument } from "@/gql/graphql" -import { ref } from "vue" +import { + AnnouncementsDocument, + AnnouncementsInput, + AnnouncementsQuery +} from "@/gql/graphql" +import { nextTick, ref, watch } from "vue" import { useApolloClient } from "@vue/apollo-composable" +import { useDisplay } from "vuetify" export const useAnnouncementsStore = defineStore("announcements", () => { - const banners = ref([]) + const banners = ref([]) - async function getBanners() { + async function getAnnouncements(input: AnnouncementsInput = {}) { const apolloClient = useApolloClient() const { data } = await apolloClient.client.query({ query: AnnouncementsDocument, - variables: { - input: { - banner: true - } - } + variables: { input } }) - banners.value = data.announcements + return data.announcements } + const navbarOffset = ref(0) + const display = useDisplay() + + watch( + () => [banners.value, display.width.value, display.height.value], + async () => { + await nextTick(() => { + let offset = 64 + for (const banner of banners.value) { + const element = document.getElementById(`banner-${banner.id}`) + if (element) { + offset += element.clientHeight + } + } + navbarOffset.value = offset + }) + } + ) + return { banners, - getBanners + getAnnouncements, + navbarOffset } }) diff --git a/src/styles/index.css b/src/styles/index.css index f7b3dd4..642f215 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -70,4 +70,9 @@ .v-list-item--variant-outlined { border-color: hsla(0, 0%, 100%, 0.12) !important; +} + +.v-btn { + letter-spacing: inherit !important; + text-transform: inherit !important; } \ No newline at end of file diff --git a/typed-router.d.ts b/typed-router.d.ts index 574d523..71e8d66 100644 --- a/typed-router.d.ts +++ b/typed-router.d.ts @@ -19,7 +19,9 @@ declare module 'vue-router/auto-routes' { */ export interface RouteNamedMap { '/': RouteRecordInfo<'/', '/', Record, Record>, - '/404': RouteRecordInfo<'/404', '/404', Record, Record>, + '/[...path]': RouteRecordInfo<'/[...path]', '/:path(.*)', { path: ParamValue }, { path: ParamValue }>, '/contact': RouteRecordInfo<'/contact', '/contact', Record, Record>, + '/news/': RouteRecordInfo<'/news/', '/news', Record, Record>, + '/news/[id]': RouteRecordInfo<'/news/[id]', '/news/:id', { id: ParamValue }, { id: ParamValue }>, } } diff --git a/yarn.lock b/yarn.lock index 71ea071..ca594b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1309,6 +1309,24 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/linkify-it@^5": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-5.0.0.tgz#21413001973106cda1c3a9b91eedd4ccd5469d76" + integrity sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q== + +"@types/markdown-it@^14.1.2": + version "14.1.2" + resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-14.1.2.tgz#57f2532a0800067d9b934f3521429a2e8bfb4c61" + integrity sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog== + dependencies: + "@types/linkify-it" "^5" + "@types/mdurl" "^2" + +"@types/mdurl@^2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-2.0.0.tgz#d43878b5b20222682163ae6f897b20447233bdfd" + integrity sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg== + "@types/node@*": version "22.5.4" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.4.tgz#83f7d1f65bc2ed223bdbf57c7884f1d5a4fa84e8" @@ -2311,6 +2329,11 @@ dataloader@^2.2.2: resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.2.2.tgz#216dc509b5abe39d43a9b9d97e6e5e473dfbe3e0" integrity sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g== +dayjs@^1.11.13: + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + de-indent@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" @@ -2429,7 +2452,7 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -entities@^4.5.0: +entities@^4.4.0, entities@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== @@ -3623,6 +3646,13 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +linkify-it@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421" + integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ== + dependencies: + uc.micro "^2.0.0" + listr2@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5" @@ -3739,6 +3769,23 @@ map-cache@^0.2.0: resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== +markdown-it@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45" + integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg== + dependencies: + argparse "^2.0.1" + entities "^4.4.0" + linkify-it "^5.0.0" + mdurl "^2.0.0" + punycode.js "^2.3.1" + uc.micro "^2.1.0" + +mdurl@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0" + integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w== + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -4165,6 +4212,11 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== +prettier@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== + promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -4181,6 +4233,11 @@ prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.13.1" +punycode.js@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" + integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== + punycode@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -4838,6 +4895,11 @@ ua-parser-js@^1.0.35: resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.38.tgz#66bb0c4c0e322fe48edfe6d446df6042e62f25e2" integrity sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ== +uc.micro@^2.0.0, uc.micro@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" + integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== + ufo@^1.5.3: version "1.5.4" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.4.tgz#16d6949674ca0c9e0fbbae1fa20a71d7b1ded754"