diff --git a/client/.postcssrc.json b/client/.postcssrc.json index 8752e22e..e329b9dc 100644 --- a/client/.postcssrc.json +++ b/client/.postcssrc.json @@ -1,6 +1,7 @@ { "plugins": { "postcss-import": {}, + "postcss-nested": {}, "postcss-url": {}, "autoprefixer": {} } diff --git a/client/local.graphql b/client/local.graphql index df7e1af5..f3ee333d 100644 --- a/client/local.graphql +++ b/client/local.graphql @@ -1,3 +1,11 @@ type ModuleNode { inEditMode: Boolean! } + +type PrivateUserNode { + language: String +} + +extend type Mutation { + setLanguage(language: String!): PrivateUserNode +} diff --git a/client/package.json b/client/package.json index c08d975e..35877d51 100644 --- a/client/package.json +++ b/client/package.json @@ -97,6 +97,7 @@ "ora": "^1.2.0", "portfinder": "^1.0.13", "postcss-import": "^15.0.0", + "postcss-nested": "^6.0.1", "postcss-url": "^10.1.3", "prettier": "2.8.2", "rimraf": "^2.6.0", diff --git a/client/src/__generated__/gql.ts b/client/src/__generated__/gql.ts index 0171264c..9d624516 100644 --- a/client/src/__generated__/gql.ts +++ b/client/src/__generated__/gql.ts @@ -13,9 +13,11 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { + "\n query LanguageQuery {\n me {\n language @client\n }\n }\n ": types.LanguageQueryDocument, + "\n mutation SetLanguage($language: String!) {\n setLanguage(language: $language) @client {\n language\n }\n }\n ": types.SetLanguageDocument, "\n query ReadOnlyQuery {\n me {\n readOnly\n selectedClass {\n readOnly\n }\n }\n }\n ": types.ReadOnlyQueryDocument, "\n query ModuleTitleQuery($slug: String) {\n module(slug: $slug) {\n title\n }\n }\n ": types.ModuleTitleQueryDocument, - "\n fragment SnapshotListItem on SnapshotNode {\n id\n title\n created\n mine\n shared\n creator\n }\n": types.SnapshotListItemFragmentDoc, + "\n fragment SnapshotListItem on SnapshotNode {\n shared\n }\n": types.SnapshotListItemFragmentDoc, "\n fragment SnapshotTitle on SnapshotNode {\n title\n }\n": types.SnapshotTitleFragmentDoc, "\n query ModuleEditModeQuery($slug: String) {\n module(slug: $slug) {\n inEditMode @client\n slug\n }\n }\n": types.ModuleEditModeQueryDocument, "\n query ChapterQuery($id: ID!) {\n chapter(id: $id) {\n path\n }\n }\n ": types.ChapterQueryDocument, @@ -38,6 +40,14 @@ const documents = { */ 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 LanguageQuery {\n me {\n language @client\n }\n }\n "): (typeof documents)["\n query LanguageQuery {\n me {\n language @client\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 mutation SetLanguage($language: String!) {\n setLanguage(language: $language) @client {\n language\n }\n }\n "): (typeof documents)["\n mutation SetLanguage($language: String!) {\n setLanguage(language: $language) @client {\n language\n }\n }\n "]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -49,7 +59,7 @@ export function graphql(source: "\n query ModuleTitleQuery($slug: String) {\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 fragment SnapshotListItem on SnapshotNode {\n id\n title\n created\n mine\n shared\n creator\n }\n"): (typeof documents)["\n fragment SnapshotListItem on SnapshotNode {\n id\n title\n created\n mine\n shared\n creator\n }\n"]; +export function graphql(source: "\n fragment SnapshotListItem on SnapshotNode {\n shared\n }\n"): (typeof documents)["\n fragment SnapshotListItem on SnapshotNode {\n shared\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/client/src/__generated__/graphql.ts b/client/src/__generated__/graphql.ts index 1242080f..3e23fa30 100644 --- a/client/src/__generated__/graphql.ts +++ b/client/src/__generated__/graphql.ts @@ -824,6 +824,7 @@ export type Mutation = { leaveTeam?: Maybe; logout?: Maybe; mutateContentBlock?: Maybe; + setLanguage?: Maybe; shareSnapshot?: Maybe; spellCheck?: Maybe; syncModuleVisibility?: Maybe; @@ -987,6 +988,11 @@ export type MutationMutateContentBlockArgs = { }; +export type MutationSetLanguageArgs = { + language: Scalars['String']['input']; +}; + + export type MutationShareSnapshotArgs = { input: ShareSnapshotInput; }; @@ -1255,6 +1261,7 @@ export type PrivateUserNode = Node & { firstName: Scalars['String']['output']; id: Scalars['ID']['output']; isTeacher?: Maybe; + language?: Maybe; lastModule?: Maybe; lastName: Scalars['String']['output']; lastTopic?: Maybe; @@ -2269,6 +2276,18 @@ export type UserGroupBlockVisibility = { schoolClassId: Scalars['ID']['input']; }; +export type LanguageQueryQueryVariables = Exact<{ [key: string]: never; }>; + + +export type LanguageQueryQuery = { __typename?: 'Query', me?: { __typename?: 'PrivateUserNode', language?: string | null } | null }; + +export type SetLanguageMutationVariables = Exact<{ + language: Scalars['String']['input']; +}>; + + +export type SetLanguageMutation = { __typename?: 'Mutation', setLanguage?: { __typename?: 'PrivateUserNode', language?: string | null } | null }; + export type ReadOnlyQueryQueryVariables = Exact<{ [key: string]: never; }>; @@ -2281,7 +2300,7 @@ export type ModuleTitleQueryQueryVariables = Exact<{ export type ModuleTitleQueryQuery = { __typename?: 'Query', module?: { __typename?: 'ModuleNode', title: string } | null }; -export type SnapshotListItemFragment = { __typename?: 'SnapshotNode', id: string, title?: string | null, created: any, mine?: boolean | null, shared: boolean, creator: string } & { ' $fragmentName'?: 'SnapshotListItemFragment' }; +export type SnapshotListItemFragment = { __typename?: 'SnapshotNode', shared: boolean } & { ' $fragmentName'?: 'SnapshotListItemFragment' }; export type SnapshotTitleFragment = { __typename?: 'SnapshotNode', title?: string | null } & { ' $fragmentName'?: 'SnapshotTitleFragment' }; @@ -2323,12 +2342,14 @@ export type ModuleSolutionsQueryVariables = Exact<{ export type ModuleSolutionsQuery = { __typename?: 'Query', module?: { __typename?: 'ModuleNode', solutionsEnabled?: boolean | null, slug: string } | null }; -export const SnapshotListItemFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SnapshotListItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SnapshotNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"mine"}},{"kind":"Field","name":{"kind":"Name","value":"shared"}},{"kind":"Field","name":{"kind":"Name","value":"creator"}}]}}]} as unknown as DocumentNode; +export const SnapshotListItemFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SnapshotListItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SnapshotNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"shared"}}]}}]} as unknown as DocumentNode; export const SnapshotTitleFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SnapshotTitle"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SnapshotNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]} as unknown as DocumentNode; +export const LanguageQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LanguageQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"client"}}]}]}}]}}]} as unknown as DocumentNode; +export const SetLanguageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SetLanguage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"language"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setLanguage"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"language"},"value":{"kind":"Variable","name":{"kind":"Name","value":"language"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"client"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}}]}}]}}]} as unknown as DocumentNode; export const ReadOnlyQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ReadOnlyQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"readOnly"}},{"kind":"Field","name":{"kind":"Name","value":"selectedClass"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}}]}}]}}]} as unknown as DocumentNode; export const ModuleTitleQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ModuleTitleQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"module"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; export const ModuleEditModeQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ModuleEditModeQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"module"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"inEditMode"},"directives":[{"kind":"Directive","name":{"kind":"Name","value":"client"}}]},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]} as unknown as DocumentNode; export const ChapterQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ChapterQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"path"}}]}}]}}]} as unknown as DocumentNode; export const ContentBlockQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ContentBlockQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"contentBlock"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"path"}}]}}]}}]} as unknown as DocumentNode; -export const ModuleSnapshotsQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ModuleSnapshotsQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"module"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"metaTitle"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"topic"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}}]}},{"kind":"Field","name":{"kind":"Name","value":"snapshots"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SnapshotListItem"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SnapshotListItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SnapshotNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"mine"}},{"kind":"Field","name":{"kind":"Name","value":"shared"}},{"kind":"Field","name":{"kind":"Name","value":"creator"}}]}}]} as unknown as DocumentNode; +export const ModuleSnapshotsQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ModuleSnapshotsQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"module"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"metaTitle"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"topic"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}}]}},{"kind":"Field","name":{"kind":"Name","value":"snapshots"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SnapshotListItem"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SnapshotListItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SnapshotNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"shared"}}]}}]} as unknown as DocumentNode; export const ModuleSolutionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ModuleSolutions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"module"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"solutionsEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/client/src/components/LanguageSwitcher.vue b/client/src/components/LanguageSwitcher.vue new file mode 100644 index 00000000..d8de30b2 --- /dev/null +++ b/client/src/components/LanguageSwitcher.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/client/src/components/modules/ModuleTeaser.vue b/client/src/components/modules/ModuleTeaser.vue index ef25961f..b59d82d6 100644 --- a/client/src/components/modules/ModuleTeaser.vue +++ b/client/src/components/modules/ModuleTeaser.vue @@ -26,81 +26,79 @@ diff --git a/client/src/graphql/cache.js b/client/src/graphql/cache.js index 6b0b3953..20176f91 100644 --- a/client/src/graphql/cache.js +++ b/client/src/graphql/cache.js @@ -6,6 +6,7 @@ const showProfileSidebarVar = makeVar(false); const scrollToElementVar = makeVar(''); const currentFilterVar = makeVar(''); const helloEmailVar = makeVar(''); +const languageVar = makeVar('de'); const idToRefFactory = (__typename) => @@ -47,6 +48,16 @@ const typePolicies = { }, keyFields: ['slug'], }, + PrivateUserNode: { + fields: { + language: { + read() { + console.log(`returning language ${languageVar()}`); + return languageVar(); + }, + }, + }, + }, RoomEntryNode: { keyFields: ['slug'], }, @@ -131,5 +142,13 @@ const cache = new InMemoryCache({ // } // }; -export { showProfileSidebarVar, showNavigationSidebarVar, scrollToElementVar, currentFilterVar, helloEmailVar, cache }; +export { + showProfileSidebarVar, + showNavigationSidebarVar, + scrollToElementVar, + currentFilterVar, + helloEmailVar, + languageVar, + cache, +}; export default cache; diff --git a/client/src/graphql/gql/fragments/moduleParts.gql b/client/src/graphql/gql/fragments/moduleParts.gql index 9b42877f..36dd7b1b 100644 --- a/client/src/graphql/gql/fragments/moduleParts.gql +++ b/client/src/graphql/gql/fragments/moduleParts.gql @@ -8,6 +8,7 @@ fragment ModuleParts on ModuleNode { heroImage heroSource solutionsEnabled + language inEditMode @client level { id diff --git a/client/src/graphql/resolvers.js b/client/src/graphql/resolvers.js index 6341f350..9307a69c 100644 --- a/client/src/graphql/resolvers.js +++ b/client/src/graphql/resolvers.js @@ -4,6 +4,7 @@ import { scrollToElementVar, showNavigationSidebarVar, showProfileSidebarVar, + languageVar, } from '@/graphql/cache'; // todo: this probably can all be done with the apollo vars in the calling components, but that might need a rewrite of @@ -40,6 +41,12 @@ export const resolvers = { profile: showProfileSidebarVar(), }; }, + setLanguage: (_, { language }) => { + languageVar(language); + return { + language: languageVar(), + }; + }, // todo: does this still work? deleteModuleNodes: (_, _query, { cache }) => { Object.keys(cache.data.data) diff --git a/client/src/graphql/typedefs.js b/client/src/graphql/typedefs.js index a0dd7ad5..4674bf39 100644 --- a/client/src/graphql/typedefs.js +++ b/client/src/graphql/typedefs.js @@ -27,9 +27,14 @@ export const typeDefs = gql` inEditMode: Boolean! } + extend type PrivateUserNode { + language: String + } + type Mutation { scrollTo(scrollTo: String!): ScrollPosition helloEmail(email: String!): HelloEmail toggleSidebar(sidebar: SidebarInput!): Sidebar + setLanguage(language: String!): PrivateUserNode } `; diff --git a/client/src/pages/topic-page.vue b/client/src/pages/topic-page.vue index 14d494c2..269f2210 100644 --- a/client/src/pages/topic-page.vue +++ b/client/src/pages/topic-page.vue @@ -35,13 +35,17 @@
- +
-