mirror of
https://github.com/supabase/supabase.git
synced 2026-06-08 02:25:04 +08:00
feat(docs): code hike
This commit is contained in:
361
apps/docs/code-hike.theme.json
Normal file
361
apps/docs/code-hike.theme.json
Normal file
@@ -0,0 +1,361 @@
|
||||
{
|
||||
"name": "supabase",
|
||||
"type": "from-css",
|
||||
"tokenColors": [
|
||||
{
|
||||
"scope": ["comment", "punctuation.definition.comment", "string.comment"],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-1)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"constant",
|
||||
"entity.name.constant",
|
||||
"variable.other.constant",
|
||||
"variable.other.enummember",
|
||||
"variable.language",
|
||||
"entity"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-2)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name", "meta.export.default", "meta.definition.variable"],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-3)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"variable.parameter.function",
|
||||
"meta.jsx.children",
|
||||
"meta.block",
|
||||
"meta.tag.attributes",
|
||||
"entity.name.constant",
|
||||
"meta.object.member",
|
||||
"meta.embedded.expression"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-4)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.name.function",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-5)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.tag", "support.class.component"],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-6)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-7)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["storage", "storage.type"],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-7)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["storage.modifier.package", "storage.modifier.import", "storage.type.java"],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-4)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["string", "string punctuation.section.embedded source"],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-8)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "support",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-2)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.property-name",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-2)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "variable",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-3)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "variable.other",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-4)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "invalid.broken",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-9)",
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "invalid.deprecated",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-9)",
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "invalid.illegal",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-9)",
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "invalid.unimplemented",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-9)",
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "carriage-return",
|
||||
"settings": {
|
||||
"background": "var(--ch-7)",
|
||||
"foreground": "var(--ch-10)",
|
||||
"fontStyle": "italic underline"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "message.error",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-9)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string variable",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-2)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["source.regexp", "string.regexp"],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-8)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"string.regexp.character-class",
|
||||
"string.regexp constant.character.escape",
|
||||
"string.regexp source.ruby.embedded",
|
||||
"string.regexp string.regexp.arbitrary-repitition"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-8)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string.regexp constant.character.escape",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-6)",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "support.constant",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-2)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "support.variable",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-2)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "support.type.property-name.json",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-6)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.module-reference",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-2)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "punctuation.definition.list.begin.markdown",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-3)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.heading", "markup.heading entity.name"],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-2)",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.quote",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-6)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.italic",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-4)",
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.bold",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-4)",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.underline"],
|
||||
"settings": {
|
||||
"fontStyle": "underline"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.strikethrough"],
|
||||
"settings": {
|
||||
"fontStyle": "strikethrough"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.inline.raw",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-2)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.deleted", "meta.diff.header.from-file", "punctuation.definition.deleted"],
|
||||
"settings": {
|
||||
"background": "var(--ch-11)",
|
||||
"foreground": "var(--ch-9)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["punctuation.section.embedded"],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-7)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.inserted", "meta.diff.header.to-file", "punctuation.definition.inserted"],
|
||||
"settings": {
|
||||
"background": "var(--ch-12)",
|
||||
"foreground": "var(--ch-6)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.changed", "punctuation.definition.changed"],
|
||||
"settings": {
|
||||
"background": "var(--ch-13)",
|
||||
"foreground": "var(--ch-3)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.ignored", "markup.untracked"],
|
||||
"settings": {
|
||||
"background": "var(--ch-2)",
|
||||
"foreground": "var(--ch-14)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.diff.range",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-5)",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.diff.header",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-2)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.separator",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-2)",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.output",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-2)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"brackethighlighter.tag",
|
||||
"brackethighlighter.curly",
|
||||
"brackethighlighter.round",
|
||||
"brackethighlighter.square",
|
||||
"brackethighlighter.angle",
|
||||
"brackethighlighter.quote"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-15)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "brackethighlighter.unmatched",
|
||||
"settings": {
|
||||
"foreground": "var(--ch-9)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["constant.other.reference.link", "string.other.link"],
|
||||
"settings": {
|
||||
"foreground": "var(--ch-8)",
|
||||
"fontStyle": "underline"
|
||||
}
|
||||
}
|
||||
],
|
||||
"colors": {
|
||||
"editor.background": "var(--ch-16)",
|
||||
"editor.foreground": "var(--ch-4)",
|
||||
"editor.selectionBackground": "var(--ch-17)",
|
||||
"editor.infoForeground": "var(--ch-18)",
|
||||
"editor.rangeHighlightBackground": "var(--ch-19)",
|
||||
"editorLineNumber.foreground": "var(--ch-20)",
|
||||
"tab.activeBackground": "var(--ch-16)",
|
||||
"tab.inactiveBackground": "var(--ch-21)",
|
||||
"tab.activeForeground": "var(--ch-4)",
|
||||
"tab.inactiveForeground": "var(--ch-15)",
|
||||
"tab.border": "var(--ch-22)",
|
||||
"tab.activeBorder": "var(--ch-16)",
|
||||
"tab.activeBorderTop": "var(--ch-23)",
|
||||
"tab.hoverBackground": "var(--ch-16)",
|
||||
"tab.hoverForeground": "var(--ch-15)",
|
||||
"editorGroupHeader.tabsBorder": "var(--ch-22)",
|
||||
"editorGroupHeader.tabsBackground": "var(--ch-21)",
|
||||
"list.inactiveSelectionBackground": "var(--ch-24)",
|
||||
"list.inactiveSelectionForeground": "var(--ch-4)",
|
||||
"list.hoverBackground": "var(--ch-25)",
|
||||
"list.hoverForeground": "var(--ch-4)"
|
||||
}
|
||||
}
|
||||
@@ -1,372 +0,0 @@
|
||||
module.exports = {
|
||||
name: 'Stripe Docs Blue',
|
||||
type: 'dark',
|
||||
colors: {
|
||||
'editor.background': '#232323',
|
||||
'editor.foreground': '#fafafa',
|
||||
'activityBar.background': 'var(--colors-scale2)',
|
||||
'sideBar.background': 'yellow',
|
||||
'editorGroupHeader.tabsBackground': 'var(--colors-scale2)',
|
||||
'sideBarSectionHeader.background': 'var(--colors-scale2)',
|
||||
'tab.activeBackground': 'var(--colors-scale3)',
|
||||
'tab.inactiveBackground': 'var(--colors-scale2)',
|
||||
'tab.border': 'var(--colors-scale2)',
|
||||
'input.background': '#ffffff1a',
|
||||
'panel.background': '#1A2652',
|
||||
'panel.border': '#1A2652',
|
||||
'editorWidget.background': '#0d0f2b',
|
||||
'editorWidget.foreground': '#ffffff4d',
|
||||
'editorWidget.border': 'var(--colors-scale5)',
|
||||
'list.hoverBackground': '#ffffff1a',
|
||||
'list.activeSelectionBackground': '#ffffff1a',
|
||||
'list.inactiveSelectionBackground': '#ffffff1a',
|
||||
'editor.hoverHighlightBackground': '#ffffff1a',
|
||||
'editor.selectionHighlightBackground': '#ffffff1a',
|
||||
'activityBarBadge.background': 'yellow',
|
||||
'sideBarTitle.foreground': 'var(--colors-scale2)',
|
||||
'statusBar.background': 'var(--colors-scale2)',
|
||||
},
|
||||
tokenColors: [
|
||||
{
|
||||
name: 'Comment',
|
||||
scope: ['comment', 'punctuation.definition.comment'],
|
||||
settings: {
|
||||
foreground: '#a3acb9',
|
||||
fontStyle: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Variables',
|
||||
scope: ['source', 'variable', 'variable.other.object', 'string constant.other.placeholder'],
|
||||
settings: {
|
||||
foreground: '#f5fbff',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Colors',
|
||||
scope: ['variable.other.constant', 'constant.other.color'],
|
||||
settings: {
|
||||
foreground: '#ffffff',
|
||||
fontStyle: 'bold',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Invalid',
|
||||
scope: ['invalid', 'invalid.illegal'],
|
||||
settings: {
|
||||
foreground: '#FF5370',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Keyword, Storage',
|
||||
scope: ['keyword', 'storage.type', 'storage.modifier'],
|
||||
settings: {
|
||||
foreground: '#98C1FE',
|
||||
fontStyle: 'bold',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Function',
|
||||
scope: ['entity.name.function'],
|
||||
settings: {
|
||||
foreground: '#7fd3ed',
|
||||
fontStyle: 'bold',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Tag',
|
||||
scope: ['entity.name.tag', 'meta.tag.sgml', 'markup.deleted.git_gutter'],
|
||||
settings: {
|
||||
foreground: '#98C1FE',
|
||||
fontStyle: 'bold',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Parameter, Property',
|
||||
scope: [
|
||||
'variable.parameter',
|
||||
'variable.other.object.property',
|
||||
'variable.other.property',
|
||||
'keyword.other.unit',
|
||||
'keyword.other',
|
||||
],
|
||||
settings: {
|
||||
foreground: '#F2AFE3',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Number, Constant, Function Argument, Tag Attribute, Embedded',
|
||||
scope: [
|
||||
'constant.numeric',
|
||||
'constant.language',
|
||||
'support.constant',
|
||||
'constant.character',
|
||||
'constant.escape',
|
||||
],
|
||||
settings: {
|
||||
foreground: '#f8b886',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'String, Symbols, Inherited Class, Markup Heading',
|
||||
scope: [
|
||||
'string',
|
||||
'constant.other.symbol',
|
||||
'constant.other.key',
|
||||
'entity.other.inherited-class',
|
||||
'markup.heading',
|
||||
'markup.inserted.git_gutter',
|
||||
'meta.group.braces.curly constant.other.object.key.js string.unquoted.label.js',
|
||||
],
|
||||
settings: {
|
||||
foreground: '#85d99e',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Entity Types',
|
||||
scope: ['support.type'],
|
||||
settings: {
|
||||
foreground: '#B2CCD6',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'CSS Class and Support',
|
||||
scope: [
|
||||
'source.css support.type.property-name',
|
||||
'source.sass support.type.property-name',
|
||||
'source.scss support.type.property-name',
|
||||
'source.less support.type.property-name',
|
||||
'source.stylus support.type.property-name',
|
||||
'source.postcss support.type.property-name',
|
||||
],
|
||||
settings: {
|
||||
foreground: '#B2CCD6',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Language methods',
|
||||
scope: ['variable.language'],
|
||||
settings: {
|
||||
fontStyle: 'italic',
|
||||
foreground: '#FF5370',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Attributes',
|
||||
scope: ['entity.other.attribute-name'],
|
||||
settings: {
|
||||
foreground: '#98C1FE',
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Inserted',
|
||||
scope: ['markup.inserted'],
|
||||
settings: {
|
||||
foreground: '#C3E88D',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Deleted',
|
||||
scope: ['markup.deleted'],
|
||||
settings: {
|
||||
foreground: '#FF5370',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Changed',
|
||||
scope: ['markup.changed'],
|
||||
settings: {
|
||||
foreground: '#C792EA',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Regular Expressions',
|
||||
scope: ['string.regexp'],
|
||||
settings: {
|
||||
foreground: '#89DDFF',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Escape Characters',
|
||||
scope: ['constant.character.escape'],
|
||||
settings: {
|
||||
foreground: '#89DDFF',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'URL',
|
||||
scope: ['*url*', '*link*', '*uri*'],
|
||||
settings: {
|
||||
fontStyle: 'underline',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ES7 Bind Operator',
|
||||
scope: ['source.js constant.other.object.key.js string.unquoted.label.js'],
|
||||
settings: {
|
||||
fontStyle: 'italic',
|
||||
foreground: '#FF5370',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Markdown - Plain',
|
||||
scope: ['text.html', 'punctuation.definition.list_item'],
|
||||
settings: {
|
||||
foreground: '#f5fbff',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markdown - Markup Raw Inline',
|
||||
scope: ['text.html.markdown markup.inline.raw.markdown'],
|
||||
settings: {
|
||||
foreground: '#C792EA',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markdown - Markup Raw Inline Punctuation',
|
||||
scope: ['text.html.markdown markup.inline.raw.markdown punctuation.definition.raw.markdown'],
|
||||
settings: {
|
||||
foreground: '#65737E',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markdown - Heading',
|
||||
scope: [
|
||||
'markdown.heading',
|
||||
'markup.heading | markup.heading entity.name',
|
||||
'markup.heading.markdown punctuation.definition.heading.markdown',
|
||||
],
|
||||
settings: {
|
||||
foreground: '#C3E88D',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markup - Italic',
|
||||
scope: ['markup.italic'],
|
||||
settings: {
|
||||
fontStyle: 'italic',
|
||||
foreground: '#f07178',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markup - Bold',
|
||||
scope: ['markup.bold', 'markup.bold string'],
|
||||
settings: {
|
||||
fontStyle: 'bold',
|
||||
foreground: '#f07178',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markup - Bold-Italic',
|
||||
scope: [
|
||||
'markup.bold markup.italic',
|
||||
'markup.italic markup.bold',
|
||||
'markup.quote markup.bold',
|
||||
'markup.bold markup.italic string',
|
||||
'markup.italic markup.bold string',
|
||||
'markup.quote markup.bold string',
|
||||
],
|
||||
settings: {
|
||||
fontStyle: 'bold',
|
||||
foreground: '#f07178',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markup - Underline',
|
||||
scope: ['markup.underline'],
|
||||
settings: {
|
||||
fontStyle: 'underline',
|
||||
foreground: '#F78C6C',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markdown - Blockquote',
|
||||
scope: ['markup.quote punctuation.definition.blockquote.markdown'],
|
||||
settings: {
|
||||
foreground: '#65737E',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markup - Quote',
|
||||
scope: ['markup.quote'],
|
||||
settings: {
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Markdown - Link Description',
|
||||
scope: ['string.other.link.description.title.markdown'],
|
||||
settings: {
|
||||
foreground: '#C792EA',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markdown - Link Anchor',
|
||||
scope: ['constant.other.reference.link.markdown'],
|
||||
settings: {
|
||||
foreground: '#FFCB6B',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markup - Raw Block',
|
||||
scope: ['markup.raw.block'],
|
||||
settings: {
|
||||
foreground: '#C792EA',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markdown - Raw Block Fenced',
|
||||
scope: ['markup.raw.block.fenced.markdown'],
|
||||
settings: {
|
||||
foreground: '#00000050',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markdown - Fenced Bode Block',
|
||||
scope: ['punctuation.definition.fenced.markdown'],
|
||||
settings: {
|
||||
foreground: '#00000050',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markdown - Fenced Bode Block Variable',
|
||||
scope: [
|
||||
'markup.raw.block.fenced.markdown',
|
||||
'variable.language.fenced.markdown',
|
||||
'punctuation.section.class.end',
|
||||
],
|
||||
settings: {
|
||||
foreground: '#EEFFFF',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markdown - Fenced Language',
|
||||
scope: ['variable.language.fenced.markdown'],
|
||||
settings: {
|
||||
foreground: '#65737E',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markdown - Separator',
|
||||
scope: ['meta.separator'],
|
||||
settings: {
|
||||
fontStyle: 'bold',
|
||||
foreground: '#65737E',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Markup - Table',
|
||||
scope: ['markup.table'],
|
||||
settings: {
|
||||
foreground: '#EEFFFF',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -11,7 +11,7 @@ Enable the [http extension for the `extensions` schema](https://app.supabase.com
|
||||
Then, define the following SQL functions in the SQL Editor to delete
|
||||
storage objects via the API:
|
||||
|
||||
```SQL
|
||||
```sql
|
||||
create or replace function delete_storage_object(bucket text, object text, out status int, out content text)
|
||||
returns record
|
||||
language 'plpgsql'
|
||||
@@ -52,7 +52,7 @@ $$;
|
||||
Next, add a trigger that removes any obsolete avatar whenever the
|
||||
profile is updated or deleted:
|
||||
|
||||
```SQL
|
||||
```sql
|
||||
create or replace function delete_old_avatar()
|
||||
returns trigger
|
||||
language 'plpgsql'
|
||||
@@ -89,7 +89,7 @@ Finally, delete the `public.profile` row before a user is deleted.
|
||||
If this step is omitted, you won't be able to delete users without
|
||||
first manually deleting their avatar image.
|
||||
|
||||
```SQL
|
||||
```sql
|
||||
create or replace function delete_old_profile()
|
||||
returns trigger
|
||||
language 'plpgsql'
|
||||
|
||||
@@ -22,7 +22,7 @@ import QuickstartIntro from './MDX/quickstart_intro.mdx'
|
||||
import SocialProviderSettingsSupabase from './MDX/social_provider_settings_supabase.mdx'
|
||||
import SocialProviderSetup from './MDX/social_provider_setup.mdx'
|
||||
import StorageManagement from './MDX/storage_management.mdx'
|
||||
// import { CH } from '@code-hike/mdx/components'
|
||||
import { CH } from '@code-hike/mdx/components'
|
||||
import RefHeaderSection from './reference/RefHeaderSection'
|
||||
|
||||
// Ref version specific
|
||||
@@ -59,6 +59,7 @@ const components = {
|
||||
Admonition,
|
||||
Button,
|
||||
ButtonCard,
|
||||
CH,
|
||||
CodeBlock,
|
||||
GlassPanel,
|
||||
Link,
|
||||
|
||||
@@ -41,7 +41,7 @@ _Optionally_ if you are using custom configuration with `createClient` then foll
|
||||
>
|
||||
<TabPanel id="1.0x" label="Before">
|
||||
|
||||
```ts title=src/supabaseClient.ts
|
||||
```ts src/supabaseClient.ts
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
|
||||
schema: 'custom',
|
||||
persistSession: false,
|
||||
@@ -51,7 +51,7 @@ const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
|
||||
</TabPanel>
|
||||
<TabPanel id="2.0x" label="After">
|
||||
|
||||
```ts title=src/supabaseClient.ts
|
||||
```ts src/supabaseClient.ts
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
|
||||
db: {
|
||||
schema: 'custom',
|
||||
|
||||
@@ -10,7 +10,7 @@ For `supabase-flutter`, you will be using the static `initialize()` method on `S
|
||||
|
||||
### Flutter `initialize()`
|
||||
|
||||
```dart title=main.dart
|
||||
```dart main.dart
|
||||
Future<void> main() async {
|
||||
await Supabase.initialize(url: 'https://xyzcompany.supabase.co', anonKey: 'public-anon-key');
|
||||
runApp(MyApp());
|
||||
@@ -30,7 +30,7 @@ final supabase = Supabase.instance.client;
|
||||
You can pass `headers` to initialize your Supabase client with customer headers.
|
||||
Here is an example of passing a custom auth header to Supabase client.
|
||||
|
||||
```dart title=main.dart
|
||||
```dart main.dart
|
||||
Future<void> main() async {
|
||||
await Supabase.initialize(
|
||||
url: 'https://xyzcompany.supabase.co',
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import fs from 'fs'
|
||||
|
||||
import { CodeHikeConfig, remarkCodeHike } from '@code-hike/mdx'
|
||||
import matter from 'gray-matter'
|
||||
import { serialize } from 'next-mdx-remote/serialize'
|
||||
import codeHikeTheme from '~/code-hike.theme.json' assert { type: 'json' }
|
||||
import { ICommonMarkdown } from '~/components/reference/Reference.types'
|
||||
|
||||
async function generateRefMarkdown(sections: ICommonMarkdown[], slug: string) {
|
||||
@@ -31,6 +33,14 @@ async function generateRefMarkdown(sections: ICommonMarkdown[], slug: string) {
|
||||
const fileContents = markdownExists ? fs.readFileSync(pathName, 'utf8') : ''
|
||||
const { data, content } = matter(fileContents)
|
||||
|
||||
const codeHikeOptions: CodeHikeConfig = {
|
||||
theme: codeHikeTheme,
|
||||
lineNumbers: true,
|
||||
showCopyButton: true,
|
||||
skipLanguages: [],
|
||||
autoImport: false,
|
||||
}
|
||||
|
||||
markdownContent.push({
|
||||
id: section.id,
|
||||
title: section.title,
|
||||
@@ -41,8 +51,8 @@ async function generateRefMarkdown(sections: ICommonMarkdown[], slug: string) {
|
||||
// MDX's available options, see the MDX docs for more info.
|
||||
// https://mdxjs.com/packages/mdx/#compilefile-options
|
||||
mdxOptions: {
|
||||
// remarkPlugins: [[remarkCodeHike, { autoImport: false, theme }]],
|
||||
useDynamicImport: true,
|
||||
remarkPlugins: [[remarkCodeHike, codeHikeOptions]],
|
||||
},
|
||||
// Indicates whether or not to parse the frontmatter from the mdx source
|
||||
})
|
||||
|
||||
@@ -2,22 +2,18 @@
|
||||
import nextMdx from '@next/mdx'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import rehypeSlug from 'rehype-slug'
|
||||
|
||||
//import theme from 'shiki/themes/nord.json' assert { type: 'json' }
|
||||
import { remarkCodeHike } from '@code-hike/mdx'
|
||||
|
||||
import withTM from 'next-transpile-modules'
|
||||
import withYaml from 'next-plugin-yaml'
|
||||
import configureBundleAnalyzer from '@next/bundle-analyzer'
|
||||
|
||||
import codeHikeTheme from './code-hike.theme.json' assert { type: 'json' }
|
||||
|
||||
const withBundleAnalyzer = configureBundleAnalyzer({
|
||||
enabled: process.env.ANALYZE === 'true',
|
||||
})
|
||||
|
||||
// import admonitions from 'remark-admonitions'
|
||||
|
||||
// import { remarkCodeHike } from '@code-hike/mdx'
|
||||
// import codeHikeTheme from './codeHikeTheme.js'
|
||||
|
||||
/**
|
||||
* Rewrites and redirects are handled by
|
||||
* apps/www nextjs config
|
||||
@@ -29,20 +25,18 @@ const withMDX = nextMdx({
|
||||
extension: /\.mdx?$/,
|
||||
options: {
|
||||
remarkPlugins: [
|
||||
// [
|
||||
// remarkCodeHike,
|
||||
// {
|
||||
// theme: codeHikeTheme,
|
||||
// autoImport: false,
|
||||
// lineNumbers: true,
|
||||
// showCopyButton: true,
|
||||
// },
|
||||
// ],
|
||||
[
|
||||
remarkCodeHike,
|
||||
{
|
||||
theme: codeHikeTheme,
|
||||
lineNumbers: true,
|
||||
showCopyButton: true,
|
||||
},
|
||||
],
|
||||
remarkGfm,
|
||||
],
|
||||
rehypePlugins: [rehypeSlug],
|
||||
// This is required for `MDXProvider` component
|
||||
// providerImportSource: '@mdx-js/react',
|
||||
providerImportSource: '@mdx-js/react',
|
||||
},
|
||||
})
|
||||
|
||||
@@ -62,7 +56,7 @@ const nextConfig = {
|
||||
'raw.githubusercontent.com',
|
||||
'weweb-changelog.ghost.io',
|
||||
'img.youtube.com',
|
||||
'archbee-image-uploads.s3.amazonaws.com'
|
||||
'archbee-image-uploads.s3.amazonaws.com',
|
||||
],
|
||||
},
|
||||
experimental: {
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
"dependencies": {
|
||||
"@algolia/autocomplete-js": "^1.7.2",
|
||||
"@algolia/autocomplete-plugin-recent-searches": "^1.7.2",
|
||||
"@code-hike/mdx": "^0.8.3",
|
||||
"@docsearch/react": "^3.3.0",
|
||||
"@mdx-js/loader": "^1.6.22",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import '../../../packages/ui/build/css/themes/light.css'
|
||||
import '../../../packages/ui/build/css/themes/dark.css'
|
||||
|
||||
import '../styles/ch.scss'
|
||||
import '../styles/code-hike.scss'
|
||||
import '../styles/main.scss?v=1.0.0'
|
||||
import '../styles/new-docs.scss'
|
||||
import '../styles/prism-okaidia.scss'
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { remarkCodeHike, CodeHikeConfig } from '@code-hike/mdx'
|
||||
import { CH } from '@code-hike/mdx/components'
|
||||
import { GetStaticPaths, GetStaticProps } from 'next'
|
||||
import { MDXRemote, MDXRemoteSerializeResult } from 'next-mdx-remote'
|
||||
import { serialize } from 'next-mdx-remote/serialize'
|
||||
import { join, relative } from 'path'
|
||||
import { relative } from 'path'
|
||||
import rehypeSlug from 'rehype-slug'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import codeHikeTheme from '~/code-hike.theme.json' assert { type: 'json' }
|
||||
import components from '~/components'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform'
|
||||
@@ -60,7 +63,7 @@ interface PythonClientDocsProps {
|
||||
export default function PythonClientDocs({ source, meta }: PythonClientDocsProps) {
|
||||
return (
|
||||
<Layout meta={meta}>
|
||||
<MDXRemote {...source} components={components} />
|
||||
<MDXRemote {...source} components={{ ...components, CH }} />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
@@ -116,9 +119,25 @@ export const getStaticProps: GetStaticProps<PythonClientDocsProps> = async ({ pa
|
||||
}
|
||||
}
|
||||
|
||||
const codeHikeOptions: CodeHikeConfig = {
|
||||
theme: codeHikeTheme,
|
||||
lineNumbers: true,
|
||||
showCopyButton: true,
|
||||
skipLanguages: [],
|
||||
autoImport: false,
|
||||
}
|
||||
|
||||
const mdxSource = await serialize(source, {
|
||||
scope: {
|
||||
chCodeConfig: codeHikeOptions,
|
||||
},
|
||||
mdxOptions: {
|
||||
remarkPlugins: [remarkGfm, remarkMkDocsAdmonition, [removeTitle, meta.title]],
|
||||
remarkPlugins: [
|
||||
remarkGfm,
|
||||
remarkMkDocsAdmonition,
|
||||
[removeTitle, meta.title],
|
||||
[remarkCodeHike, codeHikeOptions],
|
||||
],
|
||||
rehypePlugins: [[linkTransform, urlTransform], rehypeSlug],
|
||||
},
|
||||
})
|
||||
|
||||
@@ -90,7 +90,7 @@ const [captchaToken, setCaptchaToken] = useState()
|
||||
|
||||
Now lets add the HCaptcha component to the JSX section of our code
|
||||
|
||||
```html
|
||||
```jsx
|
||||
<HCaptcha />
|
||||
```
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ npm install @supabase/supabase-js @supabase/auth-ui-react @supabase/auth-ui-shar
|
||||
|
||||
Pass `supabaseClient` from `@supabase/supabase-js` as a prop to the component.
|
||||
|
||||
```js title=/src/index.js
|
||||
```js /src/index.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
|
||||
@@ -38,7 +38,7 @@ This renders the Auth component without any styling.
|
||||
We recommend using one of the predefined themes to style the UI.
|
||||
Import the theme you want to use and pass it to the `appearance.theme` prop.
|
||||
|
||||
```js lines=4,16 title=/src/index.js
|
||||
```js mark=4,16 /src/index.js
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
import {
|
||||
// Import predefined theme
|
||||
@@ -63,7 +63,7 @@ const App = () => (
|
||||
|
||||
The Auth component also supports login with [official social providers](../../auth#providers).
|
||||
|
||||
```js lines=13 title=/src/index.js
|
||||
```js mark=11 /src/index.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
import { ThemeSupa } from '@supabase/auth-ui-shared'
|
||||
@@ -81,18 +81,19 @@ const App = () => (
|
||||
|
||||
### Options
|
||||
|
||||
Options are available via 'queryParams':
|
||||
Options are available via `queryParams`:
|
||||
|
||||
```<Auth
|
||||
supabaseClient={supabase}
|
||||
providers={['google']}
|
||||
queryParams={{
|
||||
access_type: 'offline',
|
||||
prompt: 'consent',
|
||||
hd: 'domain.com'
|
||||
}}
|
||||
onlyThirdPartyProviders={true}
|
||||
/>
|
||||
```jsx
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
providers={['google']}
|
||||
queryParams={{
|
||||
access_type: 'offline',
|
||||
prompt: 'consent',
|
||||
hd: 'domain.com',
|
||||
}}
|
||||
onlyThirdPartyProviders={true}
|
||||
/>
|
||||
```
|
||||
|
||||
### Supported Views
|
||||
@@ -122,7 +123,7 @@ There are several ways to customize Auth UI:
|
||||
|
||||
Auth UI comes with several themes to customize the appearance. Each predefined theme comes with at least two variations, a `default` variation, and a `dark` variation. You can switch between these themes using the `theme` prop. Import the theme you want to use and pass it to the `appearance.theme` prop.
|
||||
|
||||
```js lines=2,13 title=/src/index.js
|
||||
```js mark=3,14 /src/index.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
import { ThemeSupa } from '@supabase/auth-ui-shared'
|
||||
@@ -151,7 +152,7 @@ Currently there is only one predefined theme available, but we plan to add more.
|
||||
|
||||
Auth UI comes with two theme variations: `default` and `dark`. You can switch between these themes with the `theme` prop.
|
||||
|
||||
```js lines=14 title=/src/index.js
|
||||
```js mark=15 /src/index.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
import { ThemeSupa } from '@supabase/auth-ui-shared'
|
||||
@@ -177,7 +178,7 @@ If you don't pass a value to `theme` it uses the `"default"` theme. You can pass
|
||||
|
||||
Auth UI themes can be overridden using variable tokens. See the [list of variable tokens](https://github.com/supabase/auth-ui/blob/main/packages/shared/src/theming/Themes.ts).
|
||||
|
||||
```js lines=14-21 title=/src/index.js
|
||||
```js mark=12:19 /src/index.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
import { ThemeSupa } from '@supabase/auth-ui-shared'
|
||||
@@ -209,7 +210,7 @@ If you created your own theme, you may not need to override any of the them.
|
||||
You can create your own theme by following the same structure within a `appearance.theme` property.
|
||||
See the list of [tokens within a theme](https://github.com/supabase/auth-ui/blob/main/packages/shared/src/theming/Themes.ts).
|
||||
|
||||
```js title=/src/index.js
|
||||
```js /src/index.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
|
||||
@@ -259,7 +260,7 @@ You can swich between different variations of your theme with the ["theme" prop]
|
||||
You can use custom CSS classes for the following elements:
|
||||
`"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`.
|
||||
|
||||
```js title=/src/index.js
|
||||
```js /src/index.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
|
||||
@@ -287,7 +288,7 @@ const App = () => (
|
||||
You can use custom CSS inline styles for the following elements:
|
||||
`"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`.
|
||||
|
||||
```js title=/src/index.js
|
||||
```js /src/index.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
|
||||
@@ -311,7 +312,7 @@ const App = () => (
|
||||
|
||||
You can use custom labels with `localization.variables`. See the [list of labels](https://github.com/supabase/auth-ui/blob/main/packages/shared/src/localization/en.json) that can be overwritten.
|
||||
|
||||
```js title=/src/index.js
|
||||
```js mark=10:15 /src/index.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
|
||||
@@ -320,7 +321,6 @@ const supabase = createClient('<INSERT PROJECT URL>', '<INSERT PROJECT ANON API
|
||||
const App = () => (
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
//highlight-start
|
||||
localization={{
|
||||
variables: {
|
||||
sign_in: {
|
||||
@@ -329,7 +329,6 @@ const App = () => (
|
||||
},
|
||||
},
|
||||
}}
|
||||
//highlight-end
|
||||
/>
|
||||
)
|
||||
```
|
||||
|
||||
@@ -62,7 +62,7 @@ yarn add @supabase/auth-helpers-react
|
||||
|
||||
Retrieve your project URL and anon key in your project's [API settings](https://app.supabase.com/project/_/settings/api) in the Dashboard to set up the following environment variables. For local development you can set them in a `.env.local` file. See an [example](https://github.com/supabase/auth-helpers/blob/main/examples/nextjs/.env.local.example).
|
||||
|
||||
```bash title=.env.local
|
||||
```bash .env.local
|
||||
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
|
||||
```
|
||||
@@ -79,7 +79,7 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
|
||||
|
||||
Wrap your `pages/_app.js` component with the `SessionContextProvider` component:
|
||||
|
||||
```jsx title=pages/_app.js
|
||||
```jsx pages/_app.js
|
||||
import { createPagesBrowserClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { SessionContextProvider } from '@supabase/auth-helpers-react'
|
||||
import { useState } from 'react'
|
||||
@@ -104,7 +104,7 @@ function MyApp({ Component, pageProps }) {
|
||||
|
||||
Wrap your `pages/_app.tsx` component with the `SessionContextProvider` component:
|
||||
|
||||
```tsx lines=2,8 title=pages/_app.tsx
|
||||
```tsx mark=2,8 pages/_app.tsx
|
||||
import { createPagesBrowserClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { SessionContextProvider, Session } from '@supabase/auth-helpers-react'
|
||||
import { useState } from 'react'
|
||||
@@ -148,7 +148,7 @@ The `Code Exchange` API route is required for the [server-side auth flow](https:
|
||||
|
||||
Create a new file at `pages/api/auth/callback.js` and populate with the following:
|
||||
|
||||
```jsx title="pages/api/auth/callback.js"
|
||||
```jsx pages/api/auth/callback.js
|
||||
import { NextApiHandler } from 'next'
|
||||
import { createPagesServerClient } from '@supabase/auth-helpers-nextjs'
|
||||
|
||||
@@ -172,7 +172,7 @@ export default handler
|
||||
|
||||
Create a new file at `pages/api/auth/callback.ts` and populate with the following:
|
||||
|
||||
```tsx title="pages/api/auth/callback.ts"
|
||||
```tsx pages/api/auth/callback.ts
|
||||
import { NextApiHandler } from 'next'
|
||||
import { createPagesServerClient } from '@supabase/auth-helpers-nextjs'
|
||||
|
||||
@@ -242,7 +242,7 @@ export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
|
||||
For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to use the `supabaseClient` from the `useSupabaseClient` hook and only run your query once the user is defined client-side in the `useUser()` hook:
|
||||
|
||||
```jsx lines=10-17
|
||||
```jsx mark=10:17
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
import { ThemeSupa } from '@supabase/auth-ui-shared'
|
||||
import { useUser, useSupabaseClient } from '@supabase/auth-helpers-react'
|
||||
@@ -291,7 +291,7 @@ export default LoginPage
|
||||
|
||||
Create a server supabase client to retrieve the logged in user's session:
|
||||
|
||||
```jsx title=pages/profile.js
|
||||
```jsx pages/profile.js
|
||||
import { createPagesServerClient } from '@supabase/auth-helpers-nextjs'
|
||||
|
||||
export default function Profile({ user }) {
|
||||
@@ -553,7 +553,7 @@ Create a server supabase client to retrieve the logged in user's session:
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title=pages/api/protected-route.js
|
||||
```jsx pages/api/protected-route.js
|
||||
import { createPagesServerClient } from '@supabase/auth-helpers-nextjs'
|
||||
|
||||
const ProtectedRoute = async (req, res) => {
|
||||
@@ -581,7 +581,7 @@ export default ProtectedRoute
|
||||
</TabPanel>
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title=pages/api/protected-route.ts
|
||||
```tsx pages/api/protected-route.ts
|
||||
import { NextApiHandler } from 'next'
|
||||
import { createPagesServerClient } from '@supabase/auth-helpers-nextjs'
|
||||
|
||||
@@ -614,7 +614,7 @@ export default ProtectedRoute
|
||||
|
||||
As an alternative to protecting individual pages you can use a [Next.js Middleware](https://nextjs.org/docs/middleware) to protect the entire directory or those that match the config object. In the following example, all requests to `/middleware-protected/*` will check whether a user is signed in, if successful the request will be forwarded to the destination route, otherwise the user will be redirected:
|
||||
|
||||
```ts title=middleware.ts
|
||||
```ts middleware.ts
|
||||
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { NextResponse } from 'next/server'
|
||||
import type { NextRequest } from 'next/server'
|
||||
@@ -698,7 +698,7 @@ Use `createPagesServerClient` within your `NextApiHandler`:
|
||||
>
|
||||
<TabPanel id="before" label="Before">
|
||||
|
||||
```tsx title=pages/api/protected-route.ts
|
||||
```tsx pages/api/protected-route.ts
|
||||
import { withApiAuth } from '@supabase/auth-helpers-nextjs'
|
||||
|
||||
export default withApiAuth(async function ProtectedRoute(req, res, supabase) {
|
||||
@@ -711,7 +711,7 @@ export default withApiAuth(async function ProtectedRoute(req, res, supabase) {
|
||||
</TabPanel>
|
||||
<TabPanel id="after" label="After">
|
||||
|
||||
```tsx title=pages/api/protected-route.ts
|
||||
```tsx pages/api/protected-route.ts
|
||||
import { NextApiHandler } from 'next'
|
||||
import { createPagesServerClient } from '@supabase/auth-helpers-nextjs'
|
||||
|
||||
@@ -752,7 +752,7 @@ Use `createPagesServerClient` within `getServerSideProps`:
|
||||
>
|
||||
<TabPanel id="before" label="Before">
|
||||
|
||||
```tsx title=pages/profile.tsx
|
||||
```tsx pages/profile.tsx
|
||||
import { withPageAuth, User } from '@supabase/auth-helpers-nextjs'
|
||||
|
||||
export default function Profile({ user }: { user: User }) {
|
||||
@@ -765,7 +765,7 @@ export const getServerSideProps = withPageAuth({ redirectTo: '/' })
|
||||
</TabPanel>
|
||||
<TabPanel id="after" label="After">
|
||||
|
||||
```tsx title=pages/profile.js
|
||||
```tsx pages/profile.js
|
||||
import { createPagesServerClient, User } from '@supabase/auth-helpers-nextjs'
|
||||
import { GetServerSidePropsContext } from 'next'
|
||||
|
||||
@@ -811,7 +811,7 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
|
||||
>
|
||||
<TabPanel id="before" label="Before">
|
||||
|
||||
```tsx title=middleware.ts
|
||||
```tsx middleware.ts
|
||||
import { withMiddlewareAuth } from '@supabase/auth-helpers-nextjs'
|
||||
|
||||
export const middleware = withMiddlewareAuth({
|
||||
@@ -832,7 +832,7 @@ export const config = {
|
||||
</TabPanel>
|
||||
<TabPanel id="after" label="After">
|
||||
|
||||
```tsx title=middleware.ts
|
||||
```tsx middleware.ts
|
||||
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { NextResponse } from 'next/server'
|
||||
import type { NextRequest } from 'next/server'
|
||||
|
||||
@@ -43,7 +43,7 @@ yarn add @supabase/auth-helpers-nextjs
|
||||
|
||||
Retrieve your project's URL and anon key from your [API settings](https://app.supabase.com/project/_/settings/api), and create a `.env.local` file with the following environment variables:
|
||||
|
||||
```bash title=".env.local"
|
||||
```bash .env.local
|
||||
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
|
||||
```
|
||||
@@ -62,7 +62,7 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
|
||||
|
||||
Create a new `middleware.js` file in the root of your project and populate with the following:
|
||||
|
||||
```jsx title="middleware.js"
|
||||
```jsx middleware.js
|
||||
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { NextResponse } from 'next/server'
|
||||
|
||||
@@ -80,7 +80,7 @@ export async function middleware(req) {
|
||||
|
||||
Create a new `middleware.ts` file in the root of your project and populate with the following:
|
||||
|
||||
```tsx title="middleware.ts"
|
||||
```tsx middleware.ts
|
||||
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { NextResponse } from 'next/server'
|
||||
|
||||
@@ -116,7 +116,7 @@ The `Code Exchange` route is required for the [server-side auth flow](https://su
|
||||
|
||||
Create a new file at `app/auth/callback/route.js` and populate with the following:
|
||||
|
||||
```jsx title="app/auth/callback.route.js"
|
||||
```jsx app/auth/callback.route.js
|
||||
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextResponse } from 'next/server'
|
||||
@@ -141,7 +141,7 @@ export async function GET(request) {
|
||||
|
||||
Create a new file at `app/auth/callback/route.ts` and populate with the following:
|
||||
|
||||
```tsx title="app/auth/callback.route.ts"
|
||||
```tsx app/auth/callback.route.ts
|
||||
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { cookies } from 'next/headers'
|
||||
import { NextResponse } from 'next/server'
|
||||
@@ -186,7 +186,7 @@ Client Components can be used to trigger the authentication process from event h
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title="app/login.js"
|
||||
```jsx app/login.js
|
||||
'use client'
|
||||
|
||||
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'
|
||||
@@ -244,7 +244,7 @@ export default function Login() {
|
||||
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title="app/login.ts"
|
||||
```tsx app/login.ts
|
||||
'use client'
|
||||
|
||||
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'
|
||||
@@ -319,7 +319,7 @@ The combination of [Server Components](https://nextjs.org/docs/getting-started/r
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title="app/login.js"
|
||||
```jsx app/login.js
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import { cookies } from 'next/headers'
|
||||
@@ -379,7 +379,7 @@ export default async function Login() {
|
||||
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title="app/login.ts"
|
||||
```tsx app/login.ts
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import { cookies } from 'next/headers'
|
||||
@@ -456,7 +456,7 @@ export default async function Login() {
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title="app/client/page.jsx"
|
||||
```jsx app/client/page.jsx
|
||||
'use client'
|
||||
|
||||
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'
|
||||
@@ -483,7 +483,7 @@ export default function Home() {
|
||||
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```jsx title="app/new-post.tsx"
|
||||
```jsx app/new-post.tsx
|
||||
"use client";
|
||||
|
||||
import { createClientComponentClient } from "@supabase/auth-helpers-nextjs";
|
||||
@@ -543,7 +543,7 @@ const supabase = createClientComponentClient({ isSingleton: false })
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title="app/page.jsx"
|
||||
```jsx app/page.jsx
|
||||
import { cookies } from 'next/headers'
|
||||
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'
|
||||
|
||||
@@ -558,7 +558,7 @@ export default async function Home() {
|
||||
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title="app/page.tsx"
|
||||
```tsx app/page.tsx
|
||||
import { cookies } from 'next/headers'
|
||||
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'
|
||||
|
||||
@@ -592,7 +592,7 @@ export default async function ServerComponent() {
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title="app/new-post.jsx"
|
||||
```jsx app/new-post.jsx
|
||||
import { cookies } from 'next/headers'
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { revalidatePath } from 'next/cache'
|
||||
@@ -619,7 +619,7 @@ export default async function NewTodo() {
|
||||
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title="app/new-post.tsx"
|
||||
```tsx app/new-post.tsx
|
||||
import { cookies } from 'next/headers'
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { revalidatePath } from 'next/cache'
|
||||
@@ -661,7 +661,7 @@ export default async function NewTodo() {
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title="app/api/todos/route.jsx"
|
||||
```jsx app/api/todos/route.jsx
|
||||
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { cookies } from 'next/headers'
|
||||
@@ -678,7 +678,7 @@ export async function POST(request) {
|
||||
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title="app/api/todos/route.tsx"
|
||||
```tsx app/api/todos/route.tsx
|
||||
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { cookies } from 'next/headers'
|
||||
|
||||
@@ -56,7 +56,7 @@ This library supports the following tooling versions:
|
||||
|
||||
Retrieve your project URL and anon key in your project's [API settings](https://app.supabase.com/project/_/settings/api) in the Dashboard to set up the following environment variables. For local development you can set them in a `.env` file. See an [example](https://github.com/supabase/auth-helpers/blob/main/examples/remix/.env.example).
|
||||
|
||||
```bash title=.env
|
||||
```bash .env
|
||||
SUPABASE_URL=YOUR_SUPABASE_URL
|
||||
SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
```
|
||||
@@ -75,7 +75,7 @@ The `Code Exchange` route is required for the [server-side auth flow](https://su
|
||||
|
||||
Create a new file at `app/routes/auth.callback.jsx` and populate with the following:
|
||||
|
||||
```jsx title="app/routes/auth.callback.jsx"
|
||||
```jsx app/routes/auth.callback.jsx
|
||||
import { redirect } from '@remix-run/node'
|
||||
import { createServerClient } from '@supabase/auth-helpers-remix'
|
||||
|
||||
@@ -105,7 +105,7 @@ export const loader = async ({ request }) => {
|
||||
|
||||
Create a new file at `app/routes/auth.callback.tsx` and populate with the following:
|
||||
|
||||
```tsx title="app/routes/auth.callback.tsx"
|
||||
```tsx app/routes/auth.callback.tsx
|
||||
import { redirect } from '@remix-run/node'
|
||||
import { createServerClient } from '@supabase/auth-helpers-remix'
|
||||
|
||||
@@ -328,7 +328,7 @@ Since our environment variables are not available client-side, we need to plumb
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title=app/root.jsx
|
||||
```jsx app/root.jsx
|
||||
export const loader = () => {
|
||||
const env = {
|
||||
SUPABASE_URL: process.env.SUPABASE_URL,
|
||||
@@ -343,26 +343,26 @@ export const loader = () => {
|
||||
|
||||
Next, we call the `useLoaderData` hook in our component to get the `env` object.
|
||||
|
||||
```jsx title=app/root.jsx
|
||||
```jsx app/root.jsx
|
||||
const { env } = useLoaderData()
|
||||
```
|
||||
|
||||
We then want to instantiate a single instance of a Supabase browser client, to be used across our client-side components.
|
||||
|
||||
```jsx title=app/root.jsx
|
||||
```jsx app/root.jsx
|
||||
const [supabase] = useState(() => createBrowserClient(env.SUPABASE_URL, env.SUPABASE_ANON_KEY))
|
||||
```
|
||||
|
||||
And then we can share this instance across our application with Outlet Context.
|
||||
|
||||
```jsx title=app/root.jsx
|
||||
```jsx app/root.jsx
|
||||
<Outlet context={{ supabase }} />
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title=app/root.tsx
|
||||
```tsx app/root.tsx
|
||||
export const loader = ({}: LoaderArgs) => {
|
||||
const env = {
|
||||
SUPABASE_URL: process.env.SUPABASE_URL!,
|
||||
@@ -377,13 +377,13 @@ export const loader = ({}: LoaderArgs) => {
|
||||
|
||||
Next, we call the `useLoaderData` hook in our component to get the `env` object.
|
||||
|
||||
```tsx title=app/root.tsx
|
||||
```tsx app/root.tsx
|
||||
const { env } = useLoaderData<typeof loader>()
|
||||
```
|
||||
|
||||
We then want to instantiate a single instance of a Supabase browser client, to be used across our client-side components.
|
||||
|
||||
```tsx title=app/root.tsx
|
||||
```tsx app/root.tsx
|
||||
const [supabase] = useState(() =>
|
||||
createBrowserClient<Database>(env.SUPABASE_URL, env.SUPABASE_ANON_KEY)
|
||||
)
|
||||
@@ -391,7 +391,7 @@ const [supabase] = useState(() =>
|
||||
|
||||
And then we can share this instance across our application with Outlet Context.
|
||||
|
||||
```tsx title=app/root.tsx
|
||||
```tsx app/root.tsx
|
||||
<Outlet context={{ supabase }} />
|
||||
```
|
||||
|
||||
@@ -417,7 +417,7 @@ Let's pipe that through from our loader.
|
||||
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title=app/root.jsx
|
||||
```jsx app/root.jsx
|
||||
export const loader = async ({ request }) => {
|
||||
const env = {
|
||||
SUPABASE_URL: process.env.SUPABASE_URL,
|
||||
@@ -451,7 +451,7 @@ export const loader = async ({ request }) => {
|
||||
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title=app/root.tsx
|
||||
```tsx app/root.tsx
|
||||
export const loader = async ({ request }: LoaderArgs) => {
|
||||
const env = {
|
||||
SUPABASE_URL: process.env.SUPABASE_URL!,
|
||||
@@ -496,7 +496,7 @@ And then use the revalidator, inside the `onAuthStateChange` hook.
|
||||
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title=app/root.jsx
|
||||
```jsx app/root.jsx
|
||||
const { env, session } = useLoaderData()
|
||||
const { revalidate } = useRevalidator()
|
||||
|
||||
@@ -524,7 +524,7 @@ useEffect(() => {
|
||||
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title=app/root.tsx
|
||||
```tsx app/root.tsx
|
||||
const { env, session } = useLoaderData<typeof loader>()
|
||||
const { revalidate } = useRevalidator()
|
||||
|
||||
@@ -569,7 +569,7 @@ Now we can use our outlet context to access our single instance of Supabase and
|
||||
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title=app/components/login.jsx
|
||||
```jsx app/components/login.jsx
|
||||
export default function Login() {
|
||||
const { supabase } = useOutletContext()
|
||||
|
||||
@@ -607,7 +607,7 @@ export default function Login() {
|
||||
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title=app/components/login.tsx
|
||||
```tsx app/components/login.tsx
|
||||
export default function Login() {
|
||||
const { supabase } = useOutletContext<{ supabase: SupabaseClient<Database> }>()
|
||||
|
||||
@@ -656,7 +656,7 @@ export default function Login() {
|
||||
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title=app/routes/realtime.jsx
|
||||
```jsx app/routes/realtime.jsx
|
||||
import { useLoaderData, useOutletContext } from '@remix-run/react'
|
||||
import { createServerClient } from '@supabase/auth-helpers-remix'
|
||||
import { json } from '@remix-run/node'
|
||||
@@ -704,7 +704,7 @@ export default function Index() {
|
||||
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title=app/routes/realtime.tsx
|
||||
```tsx app/routes/realtime.tsx
|
||||
import { useLoaderData, useOutletContext } from '@remix-run/react'
|
||||
import { createServerClient } from '@supabase/auth-helpers-remix'
|
||||
import { json } from '@remix-run/node'
|
||||
|
||||
@@ -33,7 +33,7 @@ PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
||||
|
||||
Create a server supabase client in a handle hook:
|
||||
|
||||
```ts title=src/hooks.server.ts
|
||||
```ts src/hooks.server.ts
|
||||
// src/hooks.server.ts
|
||||
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'
|
||||
import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit'
|
||||
@@ -77,7 +77,7 @@ export const handle: Handle = async ({ event, resolve }) => {
|
||||
|
||||
In order to make the session available to the UI (pages, layouts) we need to pass the session in the root layout server load function:
|
||||
|
||||
```ts title=src/routes/+layout.server.ts
|
||||
```ts src/routes/+layout.server.ts
|
||||
// src/routes/+layout.server.ts
|
||||
import type { LayoutServerLoad } from './$types'
|
||||
|
||||
@@ -398,7 +398,7 @@ In version 0.9 we now setup our Supabase client for the server inside of a `hook
|
||||
>
|
||||
<TabPanel id="older-0.8" label="0.8.x">
|
||||
|
||||
```js title=src/lib/db.ts
|
||||
```js src/lib/db.ts
|
||||
// src/lib/db.ts
|
||||
import { createClient } from '@supabase/auth-helpers-sveltekit'
|
||||
import { env } from '$env/dynamic/public'
|
||||
@@ -412,7 +412,7 @@ export const supabaseClient = createClient(env.PUBLIC_SUPABASE_URL, env.PUBLIC_S
|
||||
</TabPanel>
|
||||
<TabPanel id="0.9.0" label="0.9.0">
|
||||
|
||||
```js title=src/hooks.server.ts
|
||||
```js src/hooks.server.ts
|
||||
// src/hooks.server.ts
|
||||
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'
|
||||
import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit'
|
||||
@@ -460,7 +460,7 @@ In order to use the Supabase library in your client code you will need to setup
|
||||
>
|
||||
<TabPanel id="older-0.8" label="0.8.x">
|
||||
|
||||
```html title=src/routes/+layout.svelte
|
||||
```html src/routes/+layout.svelte
|
||||
<!-- src/routes/+layout.svelte -->
|
||||
<script lang="ts">
|
||||
import { supabaseClient } from '$lib/db'
|
||||
@@ -486,7 +486,7 @@ In order to use the Supabase library in your client code you will need to setup
|
||||
</TabPanel>
|
||||
<TabPanel id="0.9.0" label="0.9.0">
|
||||
|
||||
```ts title=src/routes/+layout.ts
|
||||
```ts src/routes/+layout.ts
|
||||
// src/routes/+layout.ts
|
||||
import { invalidate } from '$app/navigation'
|
||||
import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
|
||||
@@ -512,7 +512,7 @@ export const load: LayoutLoad = async ({ fetch, data, depends }) => {
|
||||
}
|
||||
```
|
||||
|
||||
```svelte title=src/routes/+layout.svelte
|
||||
```svelte src/routes/+layout.svelte
|
||||
<!-- src/routes/+layout.svelte -->
|
||||
<script lang="ts">
|
||||
import { invalidate } from '$app/navigation';
|
||||
@@ -556,7 +556,7 @@ Since version 0.9 relies on `hooks.server.ts` to setup our client, we no longer
|
||||
>
|
||||
<TabPanel id="older-0-8" label="0.8.x">
|
||||
|
||||
```ts title=src/app.d.ts
|
||||
```ts src/app.d.ts
|
||||
// src/app.d.ts
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
|
||||
@@ -581,7 +581,7 @@ declare namespace App {
|
||||
</TabPanel>
|
||||
<TabPanel id="0.9.0" label="0.9.0">
|
||||
|
||||
```ts title=src/app.d.ts
|
||||
```ts src/app.d.ts
|
||||
// src/app.d.ts
|
||||
import { SupabaseClient, Session } from '@supabase/supabase-js'
|
||||
import { Database } from './DatabaseDefinitions'
|
||||
@@ -614,7 +614,7 @@ declare global {
|
||||
>
|
||||
<TabPanel id="older-0-8" label="0.8.x">
|
||||
|
||||
```html title=src/routes/profile/+page.svelte
|
||||
```html src/routes/profile/+page.svelte
|
||||
<!-- src/routes/profile/+page.svelte -->
|
||||
<script lang="ts">
|
||||
/** @type {import('./$types').PageData} */
|
||||
@@ -627,7 +627,7 @@ declare global {
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
```
|
||||
|
||||
```ts title=src/routes/profile/+page.ts
|
||||
```ts src/routes/profile/+page.ts
|
||||
// src/routes/profile/+page.ts
|
||||
import type { PageLoad } from './$types'
|
||||
import { getSupabase } from '@supabase/auth-helpers-sveltekit'
|
||||
@@ -650,7 +650,7 @@ export const load: PageLoad = async (event) => {
|
||||
</TabPanel>
|
||||
<TabPanel id="0.9.0" label="0.9.0">
|
||||
|
||||
```html title=src/routes/profile/+page.svelte
|
||||
```html src/routes/profile/+page.svelte
|
||||
<!-- src/routes/profile/+page.svelte -->
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types'
|
||||
@@ -664,7 +664,7 @@ export const load: PageLoad = async (event) => {
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
```
|
||||
|
||||
```ts title=src/routes/profile/+page.ts
|
||||
```ts src/routes/profile/+page.ts
|
||||
// src/routes/profile/+page.ts
|
||||
import type { PageLoad } from './$types'
|
||||
import { redirect } from '@sveltejs/kit'
|
||||
@@ -696,7 +696,7 @@ export const load: PageLoad = async ({ parent }) => {
|
||||
>
|
||||
<TabPanel id="older-0-8" label="0.8.x">
|
||||
|
||||
```ts title=src/routes/api/protected-route/+server.ts
|
||||
```ts src/routes/api/protected-route/+server.ts
|
||||
// src/routes/api/protected-route/+server.ts
|
||||
import type { RequestHandler } from './$types'
|
||||
import { getSupabase } from '@supabase/auth-helpers-sveltekit'
|
||||
@@ -716,7 +716,7 @@ export const GET: RequestHandler = async (event) => {
|
||||
</TabPanel>
|
||||
<TabPanel id="0.9.0" label="0.9.0">
|
||||
|
||||
```ts title=src/routes/api/protected-route/+server.ts
|
||||
```ts src/routes/api/protected-route/+server.ts
|
||||
// src/routes/api/protected-route/+server.ts
|
||||
import type { RequestHandler } from './$types'
|
||||
import { json, error } from '@sveltejs/kit'
|
||||
@@ -748,7 +748,7 @@ export const GET: RequestHandler = async ({ locals: { supabase, getSession } })
|
||||
>
|
||||
<TabPanel id="older-0.7" label="0.7.x">
|
||||
|
||||
```js title=src/lib/db.ts
|
||||
```js src/lib/db.ts
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { setupSupabaseHelpers } from '@supabase/auth-helpers-sveltekit'
|
||||
import { dev } from '$app/environment'
|
||||
@@ -773,7 +773,7 @@ setupSupabaseHelpers({
|
||||
</TabPanel>
|
||||
<TabPanel id="0.8.0" label="0.8.0">
|
||||
|
||||
```js title=src/lib/db.ts
|
||||
```js src/lib/db.ts
|
||||
import { createClient } from '@supabase/auth-helpers-sveltekit'
|
||||
import { env } from '$env/dynamic/public'
|
||||
// or use the static env
|
||||
@@ -796,7 +796,7 @@ export const supabaseClient = createClient(env.PUBLIC_SUPABASE_URL, env.PUBLIC_S
|
||||
>
|
||||
<TabPanel id="older-0.7" label="0.7.x">
|
||||
|
||||
```html title=src/routes/+layout.svelte
|
||||
```html src/routes/+layout.svelte
|
||||
<script lang="ts">
|
||||
// make sure the supabase instance is initialized on the client
|
||||
import '$lib/db'
|
||||
@@ -817,7 +817,7 @@ export const supabaseClient = createClient(env.PUBLIC_SUPABASE_URL, env.PUBLIC_S
|
||||
</TabPanel>
|
||||
<TabPanel id="0.8.0" label="0.8.0">
|
||||
|
||||
```html title=src/routes/+layout.svelte
|
||||
```html src/routes/+layout.svelte
|
||||
<script>
|
||||
import { supabaseClient } from '$lib/db'
|
||||
import { invalidate } from '$app/navigation'
|
||||
@@ -852,7 +852,7 @@ export const supabaseClient = createClient(env.PUBLIC_SUPABASE_URL, env.PUBLIC_S
|
||||
>
|
||||
<TabPanel id="older-0-7" label="0.7.x">
|
||||
|
||||
```ts title=src/hooks.server.ts
|
||||
```ts src/hooks.server.ts
|
||||
// make sure the supabase instance is initialized on the server
|
||||
import '$lib/db'
|
||||
import { dev } from '$app/environment'
|
||||
@@ -863,7 +863,7 @@ export const handle = auth()
|
||||
|
||||
**Optional** _if using additional handle methods_
|
||||
|
||||
```ts title=src/hooks.server.ts
|
||||
```ts src/hooks.server.ts
|
||||
// make sure the supabase instance is initialized on the server
|
||||
import '$lib/db'
|
||||
import { dev } from '$app/environment'
|
||||
@@ -876,12 +876,12 @@ export const handle = sequence(auth(), yourHandler)
|
||||
</TabPanel>
|
||||
<TabPanel id="0.8.0" label="0.8.0">
|
||||
|
||||
```ts title=src/hooks.server.ts
|
||||
```ts src/hooks.server.ts
|
||||
// make sure the supabase instance is initialized on the server
|
||||
import '$lib/db'
|
||||
```
|
||||
|
||||
```ts title=src/hooks.client.ts
|
||||
```ts src/hooks.client.ts
|
||||
// make sure the supabase instance is initialized on the client
|
||||
import '$lib/db'
|
||||
```
|
||||
@@ -899,7 +899,7 @@ import '$lib/db'
|
||||
>
|
||||
<TabPanel id="older-0-7" label="0.7.x">
|
||||
|
||||
```ts title=src/app.d.ts
|
||||
```ts src/app.d.ts
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
@@ -922,7 +922,7 @@ declare namespace App {
|
||||
</TabPanel>
|
||||
<TabPanel id="0.8.0" label="0.8.0">
|
||||
|
||||
```ts title=src/app.d.ts
|
||||
```ts src/app.d.ts
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
@@ -956,7 +956,7 @@ declare namespace App {
|
||||
>
|
||||
<TabPanel id="older-0-7" label="0.7.x">
|
||||
|
||||
```html title=src/routes/protected-route/+page.svelte
|
||||
```html src/routes/protected-route/+page.svelte
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types'
|
||||
|
||||
@@ -971,7 +971,7 @@ declare namespace App {
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
```
|
||||
|
||||
```ts title=src/routes/protected-route/+page.ts
|
||||
```ts src/routes/protected-route/+page.ts
|
||||
import { withAuth } from '@supabase/auth-helpers-sveltekit'
|
||||
import { redirect } from '@sveltejs/kit'
|
||||
import type { PageLoad } from './$types'
|
||||
@@ -989,7 +989,7 @@ export const load: PageLoad = withAuth(async ({ session, getSupabaseClient }) =>
|
||||
</TabPanel>
|
||||
<TabPanel id="0.8.0" label="0.8.0">
|
||||
|
||||
```html title=src/routes/protected-route/+page.svelte
|
||||
```html src/routes/protected-route/+page.svelte
|
||||
<script>
|
||||
/** @type {import('./$types').PageData} */
|
||||
export let data
|
||||
@@ -1001,7 +1001,7 @@ export const load: PageLoad = withAuth(async ({ session, getSupabaseClient }) =>
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
```
|
||||
|
||||
```ts title=src/routes/protected-route/+page.ts
|
||||
```ts src/routes/protected-route/+page.ts
|
||||
// src/routes/profile/+page.ts
|
||||
import type { PageLoad } from './$types'
|
||||
import { getSupabase } from '@supabase/auth-helpers-sveltekit'
|
||||
@@ -1034,7 +1034,7 @@ export const load: PageLoad = async (event) => {
|
||||
>
|
||||
<TabPanel id="older-0-7" label="0.7.x">
|
||||
|
||||
```ts title=src/routes/api/protected-route/+server.ts
|
||||
```ts src/routes/api/protected-route/+server.ts
|
||||
import type { RequestHandler } from './$types'
|
||||
import { withAuth } from '@supabase/auth-helpers-sveltekit'
|
||||
import { json, redirect } from '@sveltejs/kit'
|
||||
@@ -1058,7 +1058,7 @@ export const GET: RequestHandler = withAuth(async ({ session, getSupabaseClient
|
||||
</TabPanel>
|
||||
<TabPanel id="0.8.0" label="0.8.0">
|
||||
|
||||
```ts title=src/routes/api/protected-route/+server.ts
|
||||
```ts src/routes/api/protected-route/+server.ts
|
||||
import type { RequestHandler } from './$types'
|
||||
import { getSupabase } from '@supabase/auth-helpers-sveltekit'
|
||||
import { json, redirect } from '@sveltejs/kit'
|
||||
@@ -1095,7 +1095,7 @@ The environment variable prefix is now `PUBLIC_` instead of `VITE_` (e.g., `VITE
|
||||
>
|
||||
<TabPanel id="older" label="0.6.11 and below">
|
||||
|
||||
```js title=src/lib/db.ts
|
||||
```js src/lib/db.ts
|
||||
import { createSupabaseClient } from '@supabase/auth-helpers-sveltekit';
|
||||
|
||||
const { supabaseClient } = createSupabaseClient(
|
||||
@@ -1109,7 +1109,7 @@ export { supabaseClient };
|
||||
</TabPanel>
|
||||
<TabPanel id="0.7.0" label="0.7.0">
|
||||
|
||||
```js title=src/lib/db.ts
|
||||
```js src/lib/db.ts
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { setupSupabaseHelpers } from '@supabase/auth-helpers-sveltekit'
|
||||
import { dev } from '$app/environment'
|
||||
@@ -1144,7 +1144,7 @@ setupSupabaseHelpers({
|
||||
>
|
||||
<TabPanel id="older" label="0.6.11 and below">
|
||||
|
||||
```html title=src/routes/__layout.svelte
|
||||
```html src/routes/__layout.svelte
|
||||
<script>
|
||||
import { session } from '$app/stores'
|
||||
import { supabaseClient } from '$lib/db'
|
||||
@@ -1161,7 +1161,7 @@ setupSupabaseHelpers({
|
||||
|
||||
The `@supabase/auth-helpers-svelte` library is no longer required as the `@supabase/auth-helpers-sveltekit` library handles all the client-side code.
|
||||
|
||||
```html title=src/routes/+layout.svelte
|
||||
```html src/routes/+layout.svelte
|
||||
<script lang="ts">
|
||||
// make sure the supabase instance is initialized on the client
|
||||
import '$lib/db'
|
||||
@@ -1192,7 +1192,7 @@ The `@supabase/auth-helpers-svelte` library is no longer required as the `@supab
|
||||
>
|
||||
<TabPanel id="older" label="0.6.11 and below">
|
||||
|
||||
```ts title=src/hooks.ts
|
||||
```ts src/hooks.ts
|
||||
import { handleAuth } from '@supabase/auth-helpers-sveltekit'
|
||||
import type { GetSession, Handle } from '@sveltejs/kit'
|
||||
import { sequence } from '@sveltejs/kit/hooks'
|
||||
@@ -1212,7 +1212,7 @@ export const getSession: GetSession = async (event) => {
|
||||
</TabPanel>
|
||||
<TabPanel id="0.7.0" label="0.7.0">
|
||||
|
||||
```ts title=src/hooks.server.ts
|
||||
```ts src/hooks.server.ts
|
||||
// make sure the supabase instance is initialized on the server
|
||||
import '$lib/db'
|
||||
import { dev } from '$app/environment'
|
||||
@@ -1223,7 +1223,7 @@ export const handle = auth()
|
||||
|
||||
**Optional** _if using additional handle methods_
|
||||
|
||||
```ts title=src/hooks.server.ts
|
||||
```ts src/hooks.server.ts
|
||||
// make sure the supabase instance is initialized on the server
|
||||
import '$lib/db'
|
||||
import { dev } from '$app/environment'
|
||||
@@ -1246,7 +1246,7 @@ export const handle = sequence(auth(), yourHandler)
|
||||
>
|
||||
<TabPanel id="older" label="0.6.11 and below">
|
||||
|
||||
```ts title=src/app.d.ts
|
||||
```ts src/app.d.ts
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
@@ -1270,7 +1270,7 @@ declare namespace App {
|
||||
</TabPanel>
|
||||
<TabPanel id="0.7.0" label="0.7.0">
|
||||
|
||||
```ts title=src/app.d.ts
|
||||
```ts src/app.d.ts
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
@@ -1303,7 +1303,7 @@ declare namespace App {
|
||||
>
|
||||
<TabPanel id="older" label="0.6.11 and below">
|
||||
|
||||
```html title=src/routes/index.svelte
|
||||
```html src/routes/index.svelte
|
||||
<script>
|
||||
import { session } from '$app/stores'
|
||||
</script>
|
||||
@@ -1319,7 +1319,7 @@ declare namespace App {
|
||||
</TabPanel>
|
||||
<TabPanel id="0.7.0" label="0.7.0">
|
||||
|
||||
```html title=src/routes/+page.svelte
|
||||
```html src/routes/+page.svelte
|
||||
<script>
|
||||
import { page } from '$app/stores'
|
||||
</script>
|
||||
@@ -1345,7 +1345,7 @@ declare namespace App {
|
||||
>
|
||||
<TabPanel id="older" label="0.6.11 and below">
|
||||
|
||||
```html title=src/routes/protected-route.svelte
|
||||
```html src/routes/protected-route.svelte
|
||||
<script lang="ts" context="module">
|
||||
import { supabaseServerClient, withPageAuth } from '@supabase/auth-helpers-sveltekit'
|
||||
import type { Load } from './__types/protected-page'
|
||||
@@ -1378,7 +1378,7 @@ declare namespace App {
|
||||
</TabPanel>
|
||||
<TabPanel id="0.7.0" label="0.7.0">
|
||||
|
||||
```html title=src/routes/protected-route/+page.svelte
|
||||
```html src/routes/protected-route/+page.svelte
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types'
|
||||
|
||||
@@ -1393,7 +1393,7 @@ declare namespace App {
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
```
|
||||
|
||||
```ts title=src/routes/protected-route/+page.ts
|
||||
```ts src/routes/protected-route/+page.ts
|
||||
import { withAuth } from '@supabase/auth-helpers-sveltekit'
|
||||
import { redirect } from '@sveltejs/kit'
|
||||
import type { PageLoad } from './$types'
|
||||
@@ -1421,7 +1421,7 @@ export const load: PageLoad = withAuth(async ({ session, getSupabaseClient }) =>
|
||||
>
|
||||
<TabPanel id="older" label="0.6.11 and below">
|
||||
|
||||
```ts title=src/routes/api/protected-route.ts
|
||||
```ts src/routes/api/protected-route.ts
|
||||
import { supabaseServerClient, withApiAuth } from '@supabase/auth-helpers-sveltekit'
|
||||
import type { RequestHandler } from './__types/protected-route'
|
||||
|
||||
@@ -1449,7 +1449,7 @@ export const GET: RequestHandler<GetOutput> = async ({ locals, request }) =>
|
||||
</TabPanel>
|
||||
<TabPanel id="0.7.0" label="0.7.0">
|
||||
|
||||
```ts title=src/routes/api/protected-route/+server.ts
|
||||
```ts src/routes/api/protected-route/+server.ts
|
||||
import type { RequestHandler } from './$types';
|
||||
import { withAuth } from '@supabase/auth-helpers-sveltekit';
|
||||
import { json, redirect } from '@sveltejs/kit';
|
||||
|
||||
@@ -202,7 +202,7 @@ Create the following files inside the `.github/workflows` directory:
|
||||
>
|
||||
<TabPanel id="ci" label="ci.yaml">
|
||||
|
||||
```yaml title=.github/workflows/ci.yml
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
@@ -233,7 +233,7 @@ jobs:
|
||||
</TabPanel>
|
||||
<TabPanel id="staging" label="staging.yaml">
|
||||
|
||||
```yaml title=.github/workflows/staging.yml
|
||||
```yaml .github/workflows/staging.yml
|
||||
name: Deploy Migrations to Staging
|
||||
|
||||
on:
|
||||
@@ -264,7 +264,7 @@ jobs:
|
||||
</TabPanel>
|
||||
<TabPanel id="production" label="production.yaml">
|
||||
|
||||
```yaml title=.github/workflows/production.yml
|
||||
```yaml .github/workflows/production.yml
|
||||
name: Deploy Migrations to Production
|
||||
|
||||
on:
|
||||
|
||||
@@ -237,7 +237,7 @@ This loads data directly from a file into a table. There are several file format
|
||||
|
||||
For example, if you wanted to load a CSV file into your movies table:
|
||||
|
||||
```csv title=./movies.csv
|
||||
```text ./movies.csv
|
||||
"The Empire Strikes Back", "After the Rebels are brutally overpowered by the Empire on the ice planet Hoth, Luke Skywalker begins Jedi training with Yoda."
|
||||
"Return of the Jedi", "After a daring mission to rescue Han Solo from Jabba the Hutt, the Rebels dispatch to Endor to destroy the second Death Star."
|
||||
```
|
||||
|
||||
@@ -19,7 +19,7 @@ By creating a supabase client with the auth context from the function, you can d
|
||||
1. Get the user object.
|
||||
2. Run queries in the context of the user with [Row Level Security (RLS)](/docs/guides/auth/row-level-security) policies enforced.
|
||||
|
||||
```js lines=14,17-19,22-23 title=supabase/functions/select-from-table-with-auth-rls/index.ts
|
||||
```js mark=14,17:19,22:23 supabase/functions/select-from-table-with-auth-rls/index.ts
|
||||
import { serve } from 'https://deno.land/std@0.177.0/http/server.ts'
|
||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
|
||||
|
||||
|
||||
@@ -93,13 +93,12 @@ export const meta = {
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
```bash terminal
|
||||
# .env
|
||||
```bash .env
|
||||
# PostgreSQL connection string used for migrations
|
||||
DIRECT_URL="postgres://postgres:[YOUR-PASSWORD]@db.[YOUR-PROJECT-REF].supabase.co:5432/postgres"
|
||||
|
||||
# PostgreSQL connection string with pgBouncer config — used by Prisma Client
|
||||
DATABASE_URL="postgres://postgres:[YOUR-PASSWORD]@db.[YOUR-PROJECT-REF].supabase.co:6543/postgres?pgbouncer=true"
|
||||
|
||||
```
|
||||
</StepHikeCompact.Code>
|
||||
|
||||
@@ -113,9 +112,7 @@ export const meta = {
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
```file="api/prisma/schema.prisma" title="api/prisma/schema.prisma"
|
||||
// api/db/schema.prisma
|
||||
|
||||
```prisma api/prisma/schema.prisma
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
@@ -132,9 +129,7 @@ export const meta = {
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
```js
|
||||
// api/db/schema.prisma
|
||||
|
||||
```prisma api/db/schema.prisma
|
||||
model Country {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @unique
|
||||
@@ -153,9 +148,7 @@ export const meta = {
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
|
||||
```ts
|
||||
// scripts/seed.ts
|
||||
|
||||
```ts scripts/seed.ts
|
||||
import type { Prisma } from '@prisma/client'
|
||||
import { db } from 'api/src/lib/db'
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ And finally we want to save the environment variables in the `environment.ts` fi
|
||||
All we need are the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
|
||||
These variables will be exposed on the browser, and that's completely fine since we have [Row Level Security](/docs/guides/auth#row-level-security) enabled on our Database.
|
||||
|
||||
```ts title=environment.ts
|
||||
```ts environment.ts
|
||||
export const environment = {
|
||||
production: false,
|
||||
supabaseUrl: 'YOUR_SUPABASE_URL',
|
||||
@@ -50,7 +50,7 @@ export const environment = {
|
||||
|
||||
Now that we have the API credentials in place, let's create a **SupabaseService** with `ng g s supabase` to initialize the Supabase client and implement functions to communicate with the Supabase API.
|
||||
|
||||
```ts title=src/app/supabase.service.ts
|
||||
```ts src/app/supabase.service.ts
|
||||
import { Injectable } from '@angular/core'
|
||||
import {
|
||||
AuthChangeEvent,
|
||||
@@ -133,7 +133,7 @@ Optionally, update [src/styles.css](https://raw.githubusercontent.com/supabase/s
|
||||
Let's set up an Angular component to manage logins and sign ups. We'll use Magic Links, so users can sign in with their email without using passwords.
|
||||
Create an **AuthComponent** with `ng g c auth` Angular CLI command.
|
||||
|
||||
```ts title=src/app/auth/auth.component.ts
|
||||
```ts src/app/auth/auth.component.ts
|
||||
import { Component } from '@angular/core'
|
||||
import { FormBuilder } from '@angular/forms'
|
||||
import { SupabaseService } from '../supabase.service'
|
||||
@@ -174,7 +174,7 @@ export class AuthComponent {
|
||||
}
|
||||
```
|
||||
|
||||
```html title=src/app/auth/auth.component.html
|
||||
```html src/app/auth/auth.component.html
|
||||
<div class="row flex-center flex">
|
||||
<div class="col-6 form-widget" aria-live="polite">
|
||||
<h1 class="header">Supabase + Angular</h1>
|
||||
@@ -205,7 +205,7 @@ export class AuthComponent {
|
||||
Users also need a way to edit their profile details and manage their accounts after signing in.
|
||||
Create an **AccountComponent** with the `ng g c account` Angular CLI command.
|
||||
|
||||
```ts title=src/app/account/account.component.ts
|
||||
```ts src/app/account/account.component.ts
|
||||
import { Component, Input, OnInit } from '@angular/core'
|
||||
import { FormBuilder } from '@angular/forms'
|
||||
import { AuthSession } from '@supabase/supabase-js'
|
||||
@@ -295,7 +295,7 @@ export class AccountComponent implements OnInit {
|
||||
}
|
||||
```
|
||||
|
||||
```html title=src/app/account/account.component.html
|
||||
```html src/app/account/account.component.html
|
||||
<form [formGroup]="updateProfileForm" (ngSubmit)="updateProfile()" class="form-widget">
|
||||
<div>
|
||||
<label for="email">Email</label>
|
||||
@@ -326,7 +326,7 @@ export class AccountComponent implements OnInit {
|
||||
|
||||
Now that we have all the components in place, let's update **AppComponent**:
|
||||
|
||||
```ts title=src/app/app.component.ts
|
||||
```ts src/app/app.component.ts
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { SupabaseService } from './supabase.service'
|
||||
|
||||
@@ -348,7 +348,7 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
```
|
||||
|
||||
```html title=src/app/app.component.html
|
||||
```html src/app/app.component.html
|
||||
<div class="container" style="padding: 50px 0 100px 0">
|
||||
<app-account *ngIf="session; else auth" [session]="session"></app-account>
|
||||
<ng-template #auth>
|
||||
@@ -359,7 +359,7 @@ export class AppComponent implements OnInit {
|
||||
|
||||
`app.module.ts` also needs to be modified to include the `ReactiveFormsModule` from the `@angular/forms` package.
|
||||
|
||||
```ts title=src/app/app.module.ts
|
||||
```ts src/app/app.module.ts
|
||||
import { NgModule } from '@angular/core'
|
||||
import { BrowserModule } from '@angular/platform-browser'
|
||||
|
||||
@@ -397,7 +397,7 @@ Every Supabase project is configured with [Storage](/docs/guides/storage) for ma
|
||||
Let's create an avatar for the user so that they can upload a profile photo.
|
||||
Create an **AvatarComponent** with `ng g c avatar` Angular CLI command.
|
||||
|
||||
```ts title=src/app/avatar/avatar.component.ts
|
||||
```ts src/app/avatar/avatar.component.ts
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core'
|
||||
import { SafeResourceUrl, DomSanitizer } from '@angular/platform-browser'
|
||||
import { SupabaseService } from '../supabase.service'
|
||||
@@ -459,7 +459,7 @@ export class AvatarComponent {
|
||||
}
|
||||
```
|
||||
|
||||
```html title=src/app/avatar/avatar.component.html
|
||||
```html src/app/avatar/avatar.component.html
|
||||
<div>
|
||||
<img
|
||||
*ngIf="_avatarUrl"
|
||||
@@ -489,7 +489,7 @@ export class AvatarComponent {
|
||||
|
||||
And then we can add the widget on top of the **AccountComponent** html template:
|
||||
|
||||
```html title=src/app/account.component.html
|
||||
```html src/app/account.component.html
|
||||
<form [formGroup]="updateProfileForm" (ngSubmit)="updateProfile()" class="form-widget">
|
||||
<app-avatar [avatarUrl]="this.avatarUrl" (upload)="updateAvatar($event)"> </app-avatar>
|
||||
<!-- input fields -->
|
||||
@@ -498,7 +498,7 @@ And then we can add the widget on top of the **AccountComponent** html template:
|
||||
|
||||
And add an `updateAvatar` function along with an `avatarUrl` getter to the **AccountComponent** typescript file:
|
||||
|
||||
```ts title=src/app/account.component.ts
|
||||
```ts src/app/account.component.ts
|
||||
@Component({
|
||||
selector: 'app-account',
|
||||
templateUrl: './account.component.html',
|
||||
|
||||
@@ -44,7 +44,7 @@ We need the API URL and the `anon` key that you copied [earlier](#get-the-api-ke
|
||||
These variables will be exposed on the browser, and that's completely fine since we have
|
||||
[Row Level Security](/docs/guides/auth#row-level-security) enabled on our Database.
|
||||
|
||||
```ts title=lib/supabase.ts
|
||||
```ts lib/supabase.ts
|
||||
import 'react-native-url-polyfill/auto'
|
||||
import * as SecureStore from 'expo-secure-store'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
@@ -79,7 +79,7 @@ export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
|
||||
Let's set up a React Native component to manage logins and sign ups.
|
||||
Users would be able to sign in with their email and password.
|
||||
|
||||
```tsx title=components/Auth.tsx
|
||||
```tsx components/Auth.tsx
|
||||
import React, { useState } from 'react'
|
||||
import { Alert, StyleSheet, View } from 'react-native'
|
||||
import { supabase } from '../lib/supabase'
|
||||
@@ -167,7 +167,7 @@ After a user is signed in we can allow them to edit their profile details and ma
|
||||
|
||||
Let's create a new component for that called `Account.tsx`.
|
||||
|
||||
```tsx title=components/Account.tsx
|
||||
```tsx components/Account.tsx
|
||||
import { useState, useEffect } from 'react'
|
||||
import { supabase } from '../lib/supabase'
|
||||
import { StyleSheet, View, Alert } from 'react-native'
|
||||
@@ -294,7 +294,7 @@ const styles = StyleSheet.create({
|
||||
|
||||
Now that we have all the components in place, let's update `App.tsx`:
|
||||
|
||||
```tsx title=App.tsx
|
||||
```tsx App.tsx
|
||||
import 'react-native-url-polyfill/auto'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { supabase } from './lib/supabase'
|
||||
@@ -350,7 +350,7 @@ expo install react-native-document-picker
|
||||
Let's create an avatar for the user so that they can upload a profile photo.
|
||||
We can start by creating a new component:
|
||||
|
||||
```tsx title=components/Avatar.tsx
|
||||
```tsx components/Avatar.tsx
|
||||
import { useState, useEffect } from 'react'
|
||||
import { supabase } from '../lib/supabase'
|
||||
import { StyleSheet, View, Alert, Image, Button } from 'react-native'
|
||||
@@ -481,7 +481,7 @@ const styles = StyleSheet.create({
|
||||
|
||||
And then we can add the widget to the Account page:
|
||||
|
||||
```tsx title=components/Account.tsx
|
||||
```tsx components/Account.tsx
|
||||
// Import the new component
|
||||
import Avatar from './Avatar'
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ For Android, edit the `android/app/src/main/AndroidManifest.xml` file.
|
||||
|
||||
Add an intent-filter to enable deep linking:
|
||||
|
||||
```xml title=android/app/src/main/AndroidManifest.xml
|
||||
```xml android/app/src/main/AndroidManifest.xml
|
||||
<manifest ...>
|
||||
<!-- ... other tags -->
|
||||
<application ...>
|
||||
@@ -80,7 +80,7 @@ For iOS, edit the ios/Runner/Info.plist file.
|
||||
|
||||
Add CFBundleURLTypes to enable deep linking:
|
||||
|
||||
```xml title=ios/Runner/Info.plist"
|
||||
```xml ios/Runner/Info.plist"
|
||||
<!-- ... other tags -->
|
||||
<plist>
|
||||
<dict>
|
||||
@@ -113,7 +113,7 @@ Now that we have deep links ready let's initialize the Supabase client inside ou
|
||||
These variables will be exposed on the app, and that's completely fine since we have
|
||||
[Row Level Security](/docs/guides/auth#row-level-security) enabled on our Database.
|
||||
|
||||
```dart title=lib/main.dart
|
||||
```dart lib/main.dart
|
||||
Future<void> main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
@@ -130,7 +130,7 @@ Future<void> main() async {
|
||||
Let's also create a constant file to make it easier to use Supabase client.
|
||||
We will also include an extension method declaration to call `showSnackBar` with one line of code.
|
||||
|
||||
```dart title=lib/constants.dart
|
||||
```dart lib/constants.dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
@@ -158,7 +158,7 @@ extension ShowSnackBar on BuildContext {
|
||||
Let's create a splash screen that will be shown to users right after they open the app.
|
||||
This screen retrieves the current session and redirects the user accordingly.
|
||||
|
||||
```dart title=lib/pages/splash_page.dart
|
||||
```dart lib/pages/splash_page.dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supabase_quickstart/constants.dart';
|
||||
|
||||
@@ -209,7 +209,7 @@ We'll use Magic Links, so users can sign in with their email without using passw
|
||||
Notice that this page sets up a listener on the user's auth state using `onAuthStateChange`.
|
||||
A new event will fire when the user comes back to the app by clicking their magic link, which this page can catch and redirect the user accordingly.
|
||||
|
||||
```dart title=lib/pages/login_page.dart
|
||||
```dart lib/pages/login_page.dart
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
@@ -307,7 +307,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
After a user is signed in we can allow them to edit their profile details and manage their account.
|
||||
Let's create a new widget called `account_page.dart` for that.
|
||||
|
||||
```dart title=lib/pages/account_page.dart"
|
||||
```dart lib/pages/account_page.dart"
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:supabase_quickstart/components/avatar.dart';
|
||||
@@ -442,7 +442,7 @@ class _AccountPageState extends State<AccountPage> {
|
||||
|
||||
Now that we have all the components in place, let's update `lib/main.dart`:
|
||||
|
||||
```dart title=lib/main.dart
|
||||
```dart lib/main.dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:supabase_quickstart/pages/account_page.dart';
|
||||
@@ -535,7 +535,7 @@ Once you are done with all of the above, it is time to dive into coding.
|
||||
Let's create an avatar for the user so that they can upload a profile photo.
|
||||
We can start by creating a new component:
|
||||
|
||||
```dart title=lib/components/avatar.dart
|
||||
```dart lib/components/avatar.dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
@@ -631,7 +631,7 @@ class _AvatarState extends State<Avatar> {
|
||||
|
||||
And then we can add the widget to the Account page as well as some logic to update the `avatar_url` whenever the user uploads a new avatar.
|
||||
|
||||
```dart title=lib/pages/account_page.dart
|
||||
```dart lib/pages/account_page.dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:supabase_quickstart/components/avatar.dart';
|
||||
|
||||
@@ -41,7 +41,7 @@ And finally we want to save the environment variables in the `environment.ts` fi
|
||||
All we need are the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
|
||||
These variables will be exposed on the browser, and that's completely fine since we have [Row Level Security](/docs/guides/auth#row-level-security) enabled on our Database.
|
||||
|
||||
```ts title=environment.ts
|
||||
```ts environment.ts
|
||||
export const environment = {
|
||||
production: false,
|
||||
supabaseUrl: 'YOUR_SUPABASE_URL',
|
||||
@@ -51,7 +51,7 @@ export const environment = {
|
||||
|
||||
Now that we have the API credentials in place, let's create a **SupabaseService** with `ionic g s supabase` to initialize the Supabase client and implement functions to communicate with the Supabase API.
|
||||
|
||||
```ts title=src/app/supabase.service.ts
|
||||
```ts src/app/supabase.service.ts
|
||||
import { Injectable } from '@angular/core'
|
||||
import { LoadingController, ToastController } from '@ionic/angular'
|
||||
import { AuthChangeEvent, createClient, Session, SupabaseClient } from '@supabase/supabase-js'
|
||||
@@ -139,7 +139,7 @@ Create an **LoginPage** with `ionic g page login` Ionic CLI command.
|
||||
|
||||
> This guide will show the template inline, but the example app will have templateUrls
|
||||
|
||||
```ts title=src/app/login/login.page.ts
|
||||
```ts src/app/login/login.page.ts
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { SupabaseService } from '../supabase.service'
|
||||
|
||||
@@ -198,7 +198,7 @@ export class LoginPage implements OnInit {
|
||||
After a user is signed in we can allow them to edit their profile details and manage their account.
|
||||
Create an **AccountComponent** with `ionic g page account` Ionic CLI command.
|
||||
|
||||
```ts title=src/app/account.component.ts
|
||||
```ts src/app/account.component.ts
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { Router } from '@angular/router'
|
||||
import { Profile, SupabaseService } from '../supabase.service'
|
||||
@@ -292,7 +292,7 @@ export class AccountPage implements OnInit {
|
||||
|
||||
Now that we have all the components in place, let's update **AppComponent**:
|
||||
|
||||
```ts title=src/app/app.component.ts
|
||||
```ts src/app/app.component.ts
|
||||
import { Component } from '@angular/core'
|
||||
import { Router } from '@angular/router'
|
||||
import { SupabaseService } from './supabase.service'
|
||||
@@ -320,7 +320,7 @@ export class AppComponent {
|
||||
|
||||
Then update the **AppRoutingModule**
|
||||
|
||||
```ts title=src/app/app.ts"
|
||||
```ts src/app/app.ts"
|
||||
import { NgModule } from '@angular/core'
|
||||
import { PreloadAllModules, RouterModule, Routes } from '@angular/router'
|
||||
|
||||
@@ -376,7 +376,7 @@ Ionic PWA elements is a companion package that will polyfill certain browser API
|
||||
|
||||
With those packages installed we can update our `main.ts` to include an additional bootstapping call for the Ionic PWA Elements.
|
||||
|
||||
```ts title=src/main.ts
|
||||
```ts src/main.ts
|
||||
import { enableProdMode } from '@angular/core'
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
|
||||
|
||||
@@ -400,7 +400,7 @@ Then create an **AvatarComponent** with this Ionic CLI command:
|
||||
ionic g component avatar --module=/src/app/account/account.module.ts --create-module
|
||||
```
|
||||
|
||||
```ts title=src/app/avatar.component.ts
|
||||
```ts src/app/avatar.component.ts
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
|
||||
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'
|
||||
import { SupabaseService } from '../supabase.service'
|
||||
@@ -503,7 +503,7 @@ export class AvatarComponent implements OnInit {
|
||||
|
||||
And then we can add the widget on top of the **AccountComponent** html template:
|
||||
|
||||
```ts title=src/app/account.component.ts
|
||||
```ts src/app/account.component.ts
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
|
||||
@@ -40,7 +40,7 @@ npm install @supabase/supabase-js
|
||||
And finally we want to save the environment variables in a `.env`.
|
||||
All we need are the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
|
||||
|
||||
```bash title=.env
|
||||
```bash .env
|
||||
REACT_APP_SUPABASE_URL=YOUR_SUPABASE_URL
|
||||
REACT_APP_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
```
|
||||
@@ -48,7 +48,7 @@ REACT_APP_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
Now that we have the API credentials in place, let's create a helper file to initialize the Supabase client. These variables will be exposed
|
||||
on the browser, and that's completely fine since we have [Row Level Security](/docs/guides/auth#row-level-security) enabled on our Database.
|
||||
|
||||
```js title=src/supabaseClient.js
|
||||
```js src/supabaseClient.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = process.env.REACT_APP_SUPABASE_URL
|
||||
@@ -61,7 +61,7 @@ export const supabase = createClient(supabaseUrl, supabaseAnonKey)
|
||||
|
||||
Let's set up a React component to manage logins and sign ups. We'll use Magic Links, so users can sign in with their email without using passwords.
|
||||
|
||||
```jsx title=/src/pages/Login.tsx
|
||||
```jsx /src/pages/Login.tsx
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
IonButton,
|
||||
@@ -140,7 +140,7 @@ After a user is signed in we can allow them to edit their profile details and ma
|
||||
|
||||
Let's create a new component for that called `Account.tsx`.
|
||||
|
||||
```jsx title=src/pages/Account.tsx
|
||||
```jsx src/pages/Account.tsx
|
||||
import {
|
||||
IonButton,
|
||||
IonContent,
|
||||
@@ -294,7 +294,7 @@ export function AccountPage() {
|
||||
|
||||
Now that we have all the components in place, let's update `App.tsx`:
|
||||
|
||||
```jsx title=src/App.tsx
|
||||
```jsx src/App.tsx
|
||||
import { Redirect, Route } from 'react-router-dom'
|
||||
import { IonApp, IonRouterOutlet, setupIonicReact } from '@ionic/react'
|
||||
import { IonReactRouter } from '@ionic/react-router'
|
||||
@@ -370,7 +370,7 @@ Ionic PWA elements is a companion package that will polyfill certain browser API
|
||||
|
||||
With those packages installed we can update our `index.tsx` to include an additional bootstapping call for the Ionic PWA Elements.
|
||||
|
||||
```ts title=src/index.tsx
|
||||
```ts src/index.tsx
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import App from './App'
|
||||
@@ -393,7 +393,7 @@ reportWebVitals()
|
||||
|
||||
Then create an **AvatarComponent**.
|
||||
|
||||
```jsx title=src/components/Avatar.tsx
|
||||
```jsx src/components/Avatar.tsx
|
||||
import { IonIcon } from '@ionic/react';
|
||||
import { person } from 'ionicons/icons';
|
||||
import { Camera, CameraResultType } from '@capacitor/camera';
|
||||
@@ -476,7 +476,7 @@ export function Avatar({
|
||||
|
||||
And then we can add the widget to the Account page:
|
||||
|
||||
```jsx title=src/pages/Account.tsx
|
||||
```jsx src/pages/Account.tsx
|
||||
// Import the new component
|
||||
|
||||
import { Avatar } from '../components/Avatar';
|
||||
|
||||
@@ -40,7 +40,7 @@ npm install @supabase/supabase-js
|
||||
And finally we want to save the environment variables in a `.env`.
|
||||
All we need are the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
|
||||
|
||||
```bash title=.env
|
||||
```bash .env
|
||||
VUE_APP_SUPABASE_URL=YOUR_SUPABASE_URL
|
||||
VUE_APP_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
```
|
||||
@@ -48,7 +48,7 @@ VUE_APP_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
Now that we have the API credentials in place, let's create a helper file to initialize the Supabase client. These variables will be exposed
|
||||
on the browser, and that's completely fine since we have [Row Level Security](/docs/guides/auth#row-level-security) enabled on our Database.
|
||||
|
||||
```js title=src/supabase.ts"
|
||||
```js src/supabase.ts"
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
|
||||
const supabaseUrl = process.env.VUE_APP_SUPABASE_URL as string;
|
||||
@@ -61,7 +61,7 @@ export const supabase = createClient(supabaseUrl, supabaseAnonKey);
|
||||
|
||||
Let's set up a Vue component to manage logins and sign ups. We'll use Magic Links, so users can sign in with their email without using passwords.
|
||||
|
||||
```html title=/src/views/Login.vue
|
||||
```html /src/views/Login.vue
|
||||
<template>
|
||||
<ion-page>
|
||||
<ion-header>
|
||||
@@ -156,7 +156,7 @@ After a user is signed in we can allow them to edit their profile details and ma
|
||||
|
||||
Let's create a new component for that called `Account.vue`.
|
||||
|
||||
```html title=src/views/Account.vue
|
||||
```html src/views/Account.vue
|
||||
<template>
|
||||
<ion-page>
|
||||
<ion-header>
|
||||
@@ -315,7 +315,7 @@ Let's create a new component for that called `Account.vue`.
|
||||
|
||||
Now that we have all the components in place, let's update `App.vue` and our routes:
|
||||
|
||||
```ts title=src/router.index.ts
|
||||
```ts src/router.index.ts
|
||||
import { createRouter, createWebHistory } from '@ionic/vue-router'
|
||||
import { RouteRecordRaw } from 'vue-router'
|
||||
import LoginPage from '../views/Login.vue'
|
||||
@@ -341,7 +341,7 @@ const router = createRouter({
|
||||
export default router
|
||||
```
|
||||
|
||||
```html title=src/App.vue
|
||||
```html src/App.vue
|
||||
<template>
|
||||
<ion-app>
|
||||
<ion-router-outlet />
|
||||
@@ -403,7 +403,7 @@ Ionic PWA elements is a companion package that will polyfill certain browser API
|
||||
|
||||
With those packages installed we can update our `main.ts` to include an additional bootstapping call for the Ionic PWA Elements.
|
||||
|
||||
```ts title=src/main.tsx"
|
||||
```ts src/main.tsx"
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
@@ -426,7 +426,7 @@ router.isReady().then(() => {
|
||||
|
||||
Then create an **AvatarComponent**.
|
||||
|
||||
```html title=src/components/Avatar.vue
|
||||
```html src/components/Avatar.vue
|
||||
<template>
|
||||
<div class="avatar">
|
||||
<div class="avatar_wrapper" @click="uploadAvatar">
|
||||
@@ -529,7 +529,7 @@ Then create an **AvatarComponent**.
|
||||
|
||||
And then we can add the widget to the Account page:
|
||||
|
||||
```html title=src/views/Account.vue
|
||||
```html src/views/Account.vue
|
||||
<template>
|
||||
<ion-page>
|
||||
<ion-header>
|
||||
|
||||
@@ -71,7 +71,7 @@ npm install @supabase/supabase-js
|
||||
And finally we want to save the environment variables in a `.env.local`.
|
||||
All we need are the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
|
||||
|
||||
```bash title=.env.local
|
||||
```bash .env.local
|
||||
NEXT_PUBLIC_SUPABASE_URL=YOUR_SUPABASE_URL
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
```
|
||||
@@ -103,7 +103,7 @@ npm install @supabase/auth-helpers-react @supabase/auth-helpers-nextjs
|
||||
|
||||
Wrap your `pages/_app.js` component with the `SessionContextProvider` component:
|
||||
|
||||
```jsx title=pages/_app.js
|
||||
```jsx pages/_app.js
|
||||
import '../styles/globals.css'
|
||||
import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs'
|
||||
import { SessionContextProvider } from '@supabase/auth-helpers-react'
|
||||
@@ -126,7 +126,7 @@ export default MyApp
|
||||
|
||||
Wrap your `pages/_app.tsx` component with the `SessionContextProvider` component:
|
||||
|
||||
```jsx lines=2,8 title=pages/_app.tsx
|
||||
```jsx mark=2,8 pages/_app.tsx
|
||||
import '../styles/globals.css'
|
||||
import { useState } from 'react'
|
||||
import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs'
|
||||
@@ -167,7 +167,7 @@ npm install @supabase/auth-ui-react
|
||||
|
||||
Add the `Auth` component to your home page
|
||||
|
||||
```jsx title=pages/index.js
|
||||
```jsx pages/index.js
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
import { ThemeSupa } from '@supabase/auth-ui-shared'
|
||||
import { useSession, useSupabaseClient } from '@supabase/auth-helpers-react'
|
||||
@@ -204,7 +204,7 @@ After a user is signed in we can allow them to edit their profile details and ma
|
||||
|
||||
Let's create a new component for that called `Account.js` within a `components` folder.
|
||||
|
||||
```tsx title=components/Account.js
|
||||
```tsx components/Account.js
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useUser, useSupabaseClient } from '@supabase/auth-helpers-react'
|
||||
|
||||
@@ -322,7 +322,7 @@ Let's create a new component for that called `Account.tsx` within a `components`
|
||||
|
||||
First, [generate type definitions from your database using the Supabase CLI](https://supabase.com/docs/guides/database/api/generating-types) to `../utils/database.types`.
|
||||
|
||||
```tsx title=components/Account.tsx
|
||||
```tsx components/Account.tsx
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useUser, useSupabaseClient, Session } from '@supabase/auth-helpers-react'
|
||||
import { Database } from '../utils/database.types'
|
||||
@@ -452,7 +452,7 @@ export default function Account({ session }: { session: Session }) {
|
||||
|
||||
Now that we have all the components in place, let's update `pages/index.js`:
|
||||
|
||||
```jsx lines=3,14 title=pages/index.js
|
||||
```jsx mark=3,14 pages/index.js
|
||||
import { Auth } from '@supabase/auth-ui-react'
|
||||
import { ThemeSupa } from '@supabase/auth-ui-shared'
|
||||
import { useSession, useSupabaseClient } from '@supabase/auth-helpers-react'
|
||||
@@ -501,7 +501,7 @@ Let's create an avatar widget for the user so that they can upload a profile pho
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title=components/Avatar.js
|
||||
```jsx components/Avatar.js
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useSupabaseClient } from '@supabase/auth-helpers-react'
|
||||
|
||||
@@ -593,7 +593,7 @@ export default function Avatar({ uid, url, size, onUpload }) {
|
||||
</TabPanel>
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title=components/Avatar.tsx
|
||||
```tsx components/Avatar.tsx
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useSupabaseClient } from '@supabase/auth-helpers-react'
|
||||
import { Database } from '../utils/database.types'
|
||||
@@ -701,7 +701,7 @@ export default function Avatar({
|
||||
|
||||
And then we can add the widget to the Account page:
|
||||
|
||||
```jsx title=components/Account.js
|
||||
```jsx components/Account.js
|
||||
// Import the new component
|
||||
import Avatar from './Avatar'
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ npm install @nuxtjs/supabase --save-dev
|
||||
And finally we want to save the environment variables in a `.env`.
|
||||
All we need are the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
|
||||
|
||||
```bash title=.env
|
||||
```bash .env
|
||||
SUPABASE_URL="YOUR_SUPABASE_URL"
|
||||
SUPABASE_KEY="YOUR_SUPABASE_ANON_KEY"
|
||||
```
|
||||
@@ -51,7 +51,7 @@ No need to initialize Supabase. The library will take care of it automatically.
|
||||
And one optional step is to update the CSS file `assets/main.css` to make the app look nice.
|
||||
You can find the full contents of this file [here](https://github.com/supabase-community/nuxt3-quickstarter/blob/main/assets/main.css).
|
||||
|
||||
```typescript title=nuxt.config.ts
|
||||
```typescript nuxt.config.ts
|
||||
import { defineNuxtConfig } from 'nuxt'
|
||||
|
||||
// https://v3.nuxtjs.org/api/configuration/nuxt.config
|
||||
@@ -65,7 +65,7 @@ export default defineNuxtConfig({
|
||||
|
||||
Let's set up a Vue component to manage logins and sign ups. We'll use Magic Links, so users can sign in with their email without using passwords.
|
||||
|
||||
```vue title=/components/Auth.vue
|
||||
```vue /components/Auth.vue
|
||||
<script setup>
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
@@ -116,7 +116,7 @@ To access the user information, use the composable [useSupabaseUser](https://sup
|
||||
After a user is signed in we can allow them to edit their profile details and manage their account.
|
||||
Let's create a new component for that called `Account.vue`.
|
||||
|
||||
```vue title=components/Account.vue
|
||||
```vue components/Account.vue
|
||||
<script setup>
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
@@ -215,7 +215,7 @@ async function signOut() {
|
||||
|
||||
Now that we have all the components in place, let's update `app.vue`:
|
||||
|
||||
```vue title=app.vue
|
||||
```vue app.vue
|
||||
<script setup>
|
||||
const user = useSupabaseUser()
|
||||
</script>
|
||||
@@ -246,7 +246,7 @@ Every Supabase project is configured with [Storage](/docs/guides/storage) for ma
|
||||
|
||||
Let's create an avatar for the user so that they can upload a profile photo. We can start by creating a new component:
|
||||
|
||||
```vue title=components/Avatar.vue
|
||||
```vue components/Avatar.vue
|
||||
<script setup>
|
||||
const props = defineProps(['path'])
|
||||
const { path } = toRefs(props)
|
||||
@@ -337,7 +337,7 @@ watch(path, () => {
|
||||
|
||||
And then we can add the widget to the Account page:
|
||||
|
||||
```vue title=components/Account.vue
|
||||
```vue components/Account.vue
|
||||
<script setup>
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ npm install @supabase/supabase-js
|
||||
And finally we want to save the environment variables in a `.env.local` file.
|
||||
All we need are the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
|
||||
|
||||
```bash title=.env
|
||||
```bash .env
|
||||
VITE_SUPABASE_URL=YOUR_SUPABASE_URL
|
||||
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
```
|
||||
@@ -49,7 +49,7 @@ on the browser, and that's completely fine since we have [Row Level Security](/d
|
||||
|
||||
Create and edit `src/supabaseClient.js`:
|
||||
|
||||
```js title=src/supabaseClient.js
|
||||
```js src/supabaseClient.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
|
||||
@@ -67,7 +67,7 @@ Let's set up a React component to manage logins and sign ups. We'll use Magic Li
|
||||
|
||||
Create and edit `src/Auth.jsx`:
|
||||
|
||||
```jsx title=src/Auth.jsx
|
||||
```jsx src/Auth.jsx
|
||||
import { useState } from 'react'
|
||||
import { supabase } from './supabaseClient'
|
||||
|
||||
@@ -123,7 +123,7 @@ After a user is signed in we can allow them to edit their profile details and ma
|
||||
|
||||
Let's create a new component for that called `src/Account.jsx`.
|
||||
|
||||
```jsx title=src/Account.jsx
|
||||
```jsx src/Account.jsx
|
||||
import { useState, useEffect } from 'react'
|
||||
import { supabase } from './supabaseClient'
|
||||
|
||||
@@ -226,7 +226,7 @@ export default function Account({ session }) {
|
||||
|
||||
Now that we have all the components in place, let's update `src/App.jsx`:
|
||||
|
||||
```jsx title=src/App.jsx
|
||||
```jsx src/App.jsx
|
||||
import './App.css'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { supabase } from './supabaseClient'
|
||||
@@ -276,7 +276,7 @@ Let's create an avatar for the user so that they can upload a profile photo. We
|
||||
|
||||
Create and edit `src/Avatar.jsx`:
|
||||
|
||||
```jsx title=src/Avatar.jsx
|
||||
```jsx src/Avatar.jsx
|
||||
import { useEffect, useState } from 'react'
|
||||
import { supabase } from './supabaseClient'
|
||||
|
||||
@@ -365,7 +365,7 @@ export default function Avatar({ url, size, onUpload }) {
|
||||
|
||||
And then we can add the widget to the Account page at `src/Account.jsx`:
|
||||
|
||||
```jsx title=src/Account.jsx
|
||||
```jsx src/Account.jsx
|
||||
// Import the new component
|
||||
import Avatar from './Avatar'
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ Say, **yes** and it will setup the Supabase client in your app and also provide
|
||||
Next, we want to save the environment variables in a `.env`.
|
||||
We need the `API URL` as well as the `anon` and `jwt_secret` keys that you copied [earlier](#get-the-api-keys).
|
||||
|
||||
```bash title=.env
|
||||
```bash .env
|
||||
SUPABASE_URL=YOUR_SUPABASE_URL
|
||||
SUPABASE_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
SUPABASE_JWT_SECRET=YOUR_SUPABASE_JWT_SECRET
|
||||
@@ -135,7 +135,7 @@ SUPABASE_JWT_SECRET=YOUR_SUPABASE_JWT_SECRET
|
||||
|
||||
And finally, you will also need to save **just** the `web side` environment variables to the `redwood.toml`.
|
||||
|
||||
```bash title=redwood.toml
|
||||
```bash redwood.toml
|
||||
[web]
|
||||
title = "Supabase Redwood Tutorial"
|
||||
port = 8910
|
||||
@@ -153,7 +153,7 @@ since we have [Row Level Security](/docs/guides/auth#row-level-security) enabled
|
||||
|
||||
You'll see these being used to configure your Supabase client in `web/src/App.js`:
|
||||
|
||||
```js title=web/src/App.js
|
||||
```js web/src/App.js
|
||||
// ... Redwood imports
|
||||
import { AuthProvider } from '@redwoodjs/auth'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
@@ -217,7 +217,7 @@ You can stop the `dev` server if you want; to see your changes, just be sure to
|
||||
|
||||
You should see the `Home` page route in `web/src/Routes.js`:
|
||||
|
||||
```bash title=web/src/Routes.js
|
||||
```bash web/src/Routes.js
|
||||
import { Router, Route } from '@redwoodjs/router'
|
||||
|
||||
const Routes = () => {
|
||||
@@ -248,7 +248,7 @@ yarn rw g component auth
|
||||
|
||||
Now, update the `Auth.js` component to contain:
|
||||
|
||||
```jsx title=/web/src/components/Auth/Auth.js
|
||||
```jsx /web/src/components/Auth/Auth.js
|
||||
import { useState } from 'react'
|
||||
import { useAuth } from '@redwoodjs/auth'
|
||||
|
||||
@@ -321,7 +321,7 @@ yarn rw g component account
|
||||
|
||||
And then update the file to contain:
|
||||
|
||||
```jsx title=web/src/components/Account/Account.js
|
||||
```jsx web/src/components/Account/Account.js
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useAuth } from '@redwoodjs/auth'
|
||||
|
||||
@@ -453,7 +453,7 @@ of the supabase client to interact with your API.
|
||||
|
||||
Now that we have all the components in place, let's update your `HomePage` page to use them:
|
||||
|
||||
```jsx title=web/src/pages/HomePage/HomePage.js
|
||||
```jsx web/src/pages/HomePage/HomePage.js
|
||||
import { useAuth } from '@redwoodjs/auth'
|
||||
import { MetaTags } from '@redwoodjs/web'
|
||||
|
||||
@@ -506,7 +506,7 @@ yarn rw g component avatar
|
||||
|
||||
Now, update your Avatar component to contain the following widget:
|
||||
|
||||
```jsx title=web/src/components/Avatar/Avatar.js
|
||||
```jsx web/src/components/Avatar/Avatar.js
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useAuth } from '@redwoodjs/auth'
|
||||
|
||||
@@ -599,7 +599,7 @@ export default Avatar
|
||||
|
||||
And then we can add the widget to the Account component:
|
||||
|
||||
```jsx title=web/src/components/Account/Account.js
|
||||
```jsx web/src/components/Account/Account.js
|
||||
// Import the new component
|
||||
import Avatar from 'src/components/Avatar'
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ npm install @supabase/supabase-js
|
||||
And finally we want to save the environment variables in a `.env`.
|
||||
All we need are the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
|
||||
|
||||
```bash title=.env
|
||||
```bash .env
|
||||
VITE_SUPABASE_URL=YOUR_SUPABASE_URL
|
||||
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
```
|
||||
@@ -46,7 +46,7 @@ VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
Now that we have the API credentials in place, let's create a helper file to initialize the Supabase client. These variables will be exposed
|
||||
on the browser, and that's completely fine since we have [Row Level Security](/docs/guides/auth#row-level-security) enabled on our Database.
|
||||
|
||||
```js title=src/supabaseClient.jsx
|
||||
```js src/supabaseClient.jsx
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
|
||||
@@ -62,7 +62,7 @@ You can find the full contents of this file [here](https://raw.githubusercontent
|
||||
|
||||
Let's set up a SolidJS component to manage logins and sign ups. We'll use Magic Links, so users can sign in with their email without using passwords.
|
||||
|
||||
```jsx title=src/Auth.tsx
|
||||
```jsx src/Auth.tsx
|
||||
import { createSignal } from 'solid-js'
|
||||
import { supabase } from './supabaseClient'
|
||||
|
||||
@@ -122,7 +122,7 @@ After a user is signed in we can allow them to edit their profile details and ma
|
||||
|
||||
Let's create a new component for that called `Account.tsx`.
|
||||
|
||||
```tsx title=src/Account.tsx
|
||||
```tsx src/Account.tsx
|
||||
import { AuthSession } from '@supabase/supabase-js'
|
||||
import { Component, createEffect, createSignal } from 'solid-js'
|
||||
import { supabase } from './supabaseClient'
|
||||
@@ -241,7 +241,7 @@ export default Account
|
||||
|
||||
Now that we have all the components in place, let's update `App.tsx`:
|
||||
|
||||
```jsx title=src/App.tsx
|
||||
```jsx src/App.tsx
|
||||
import { Component, createEffect, createSignal } from 'solid-js'
|
||||
import { supabase } from './supabaseClient'
|
||||
import { AuthSession } from '@supabase/supabase-js'
|
||||
@@ -289,7 +289,7 @@ Every Supabase project is configured with [Storage](/docs/guides/storage) for ma
|
||||
|
||||
Let's create an avatar for the user so that they can upload a profile photo. We can start by creating a new component:
|
||||
|
||||
```jsx title=src/Avatar.tsx
|
||||
```jsx src/Avatar.tsx
|
||||
import { Component, createEffect, createSignal, JSX } from 'solid-js'
|
||||
import { supabase } from './supabaseClient'
|
||||
|
||||
@@ -392,7 +392,7 @@ export default Avatar
|
||||
|
||||
And then we can add the widget to the Account page:
|
||||
|
||||
```jsx title=src/Account.tsx
|
||||
```jsx src/Account.tsx
|
||||
// Import the new component
|
||||
import Avatar from './Avatar'
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ npm install @supabase/supabase-js
|
||||
And finally we want to save the environment variables in a `.env`.
|
||||
All we need are the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
|
||||
|
||||
```bash title=.env
|
||||
```bash .env
|
||||
VITE_SUPABASE_URL=YOUR_SUPABASE_URL
|
||||
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
```
|
||||
@@ -47,7 +47,7 @@ VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
Now that we have the API credentials in place, let's create a helper file to initialize the Supabase client. These variables will be exposed
|
||||
on the browser, and that's completely fine since we have [Row Level Security](/docs/guides/auth#row-level-security) enabled on our Database.
|
||||
|
||||
```js title=src/supabaseClient.ts
|
||||
```js src/supabaseClient.ts
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
|
||||
@@ -63,7 +63,7 @@ You can find the full contents of this file [here](https://raw.githubusercontent
|
||||
|
||||
Let's set up a Svelte component to manage logins and sign ups. We'll use Magic Links, so users can sign in with their email without using passwords.
|
||||
|
||||
```html title=src/lib/Auth.svelte
|
||||
```html src/lib/Auth.svelte
|
||||
<script lang="ts">
|
||||
import { supabase } from 'src/supabaseClient'
|
||||
|
||||
@@ -116,7 +116,7 @@ Let's set up a Svelte component to manage logins and sign ups. We'll use Magic L
|
||||
After a user is signed in we can allow them to edit their profile details and manage their account.
|
||||
Let's create a new component for that called `Account.svelte`.
|
||||
|
||||
```html title=src/lib/Account.svelte
|
||||
```html src/lib/Account.svelte
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import type { AuthSession } from "@supabase/supabase-js";
|
||||
@@ -213,7 +213,7 @@ Let's create a new component for that called `Account.svelte`.
|
||||
|
||||
Now that we have all the components in place, let's update `App.svelte`:
|
||||
|
||||
```html title=src/App.svelte
|
||||
```html src/App.svelte
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte'
|
||||
import { supabase } from './supabaseClient'
|
||||
@@ -263,7 +263,7 @@ Every Supabase project is configured with [Storage](/docs/guides/storage) for ma
|
||||
|
||||
Let's create an avatar for the user so that they can upload a profile photo. We can start by creating a new component:
|
||||
|
||||
```html title=src/lib/Avatar.svelte
|
||||
```html src/lib/Avatar.svelte
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { supabase } from '../supabaseClient'
|
||||
@@ -353,7 +353,7 @@ Let's create an avatar for the user so that they can upload a profile photo. We
|
||||
|
||||
And then we can add the widget to the Account page:
|
||||
|
||||
```html title=src/lib/Account.svelte
|
||||
```html src/lib/Account.svelte
|
||||
<script lang="ts">
|
||||
// Import the new component
|
||||
import Avatar from './Avatar.svelte'
|
||||
|
||||
@@ -40,7 +40,7 @@ npm install @supabase/supabase-js
|
||||
And finally we want to save the environment variables in a `.env`.
|
||||
All we need are the `SUPABASE_URL` and the `SUPABASE_KEY` key that you copied [earlier](#get-the-api-keys).
|
||||
|
||||
```bash title=.env
|
||||
```bash .env
|
||||
PUBLIC_SUPABASE_URL="YOUR_SUPABASE_URL"
|
||||
PUBLIC_SUPABASE_ANON_KEY="YOUR_SUPABASE_KEY"
|
||||
```
|
||||
@@ -61,7 +61,7 @@ npm install @supabase/auth-helpers-sveltekit
|
||||
|
||||
Add the code below to your `src/hooks.server.ts` to initialize the client on the server:
|
||||
|
||||
```ts title=src/hooks.server.ts
|
||||
```ts src/hooks.server.ts
|
||||
// src/hooks.server.ts
|
||||
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'
|
||||
import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit'
|
||||
@@ -94,7 +94,7 @@ export const handle: Handle = async ({ event, resolve }) => {
|
||||
|
||||
If you are using TypeScript the compiler might complain about `event.locals.supabase` and `event.locals.getSession`, this can be fixed by updating your `src/app.d.ts` with the content below:
|
||||
|
||||
```ts title=src/app.d.ts
|
||||
```ts src/app.d.ts
|
||||
// src/app.d.ts
|
||||
|
||||
import { SupabaseClient, Session } from '@supabase/supabase-js'
|
||||
@@ -116,7 +116,7 @@ declare global {
|
||||
|
||||
Create a new `src/routes/+layout.server.ts` file to handle the session on the server-side.
|
||||
|
||||
```ts title=src/routes/+layout.server.ts
|
||||
```ts src/routes/+layout.server.ts
|
||||
// src/routes/+layout.server.ts
|
||||
import type { LayoutServerLoad } from './$types'
|
||||
|
||||
@@ -131,7 +131,7 @@ export const load: LayoutServerLoad = async ({ locals: { getSession } }) => {
|
||||
|
||||
Create a new `src/routes/+layout.ts` file to handle the session and the supabase object on the client-side.
|
||||
|
||||
```ts title=src/routes/+layout.ts
|
||||
```ts src/routes/+layout.ts
|
||||
// src/routes/+layout.ts
|
||||
import { invalidate } from '$app/navigation'
|
||||
import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
|
||||
@@ -158,7 +158,7 @@ export const load: LayoutLoad = async ({ fetch, data, depends }) => {
|
||||
|
||||
Update your `src/routes/+layout.svelte`:
|
||||
|
||||
```svelte title=src/routes/+layout.svelte
|
||||
```svelte src/routes/+layout.svelte
|
||||
<!-- src/routes/+layout.svelte -->
|
||||
<script lang="ts">
|
||||
import '../styles.css';
|
||||
@@ -203,7 +203,7 @@ npm install @supabase/auth-ui-svelte @supabase/auth-ui-shared
|
||||
|
||||
Add the `Auth` component to your home page
|
||||
|
||||
```svelte title=src/routes/+page.svelte
|
||||
```svelte src/routes/+page.svelte
|
||||
<!-- src/routes/+page.svelte -->
|
||||
<script lang="ts">
|
||||
import { Auth } from '@supabase/auth-ui-svelte';
|
||||
@@ -289,7 +289,7 @@ This page is used for waiting while your client-side code inside of `src/routes/
|
||||
After a user is signed in, they need to be able to edit their profile details and manage their account.
|
||||
Create a new `src/routes/account/+page.svelte` file with the content below.
|
||||
|
||||
```svelte title=src/routes/account/+page.svelte
|
||||
```svelte src/routes/account/+page.svelte
|
||||
<!-- src/routes/account/+page.svelte -->
|
||||
<script lang="ts">
|
||||
import { enhance, type SubmitFunction } from '$app/forms';
|
||||
@@ -456,7 +456,7 @@ Every Supabase project is configured with [Storage](/docs/guides/storage) for ma
|
||||
|
||||
Let's create an avatar for the user so that they can upload a profile photo. We can start by creating a new component called `Avatar.svelte` in the `src/routes/account` directory:
|
||||
|
||||
```svelte title=src/routes/account/Avatar.svelte
|
||||
```svelte src/routes/account/Avatar.svelte
|
||||
<!-- src/routes/account/Avatar.svelte -->
|
||||
<script lang="ts">
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
@@ -554,7 +554,7 @@ Let's create an avatar for the user so that they can upload a profile photo. We
|
||||
|
||||
And then we can add the widget to the Account page:
|
||||
|
||||
```svelte title=src/routes/account/+page.svelte
|
||||
```svelte src/routes/account/+page.svelte
|
||||
<!-- src/routes/account/+page.svelte -->
|
||||
<script lang="ts">
|
||||
// Import the new component
|
||||
|
||||
@@ -44,7 +44,7 @@ npm install @supabase/supabase-js
|
||||
And finally we want to save the environment variables in a `.env`.
|
||||
All we need are the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
|
||||
|
||||
```bash title=.env
|
||||
```bash .env
|
||||
VITE_SUPABASE_URL=YOUR_SUPABASE_URL
|
||||
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
```
|
||||
@@ -52,7 +52,7 @@ VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
With the API credentials in place, create an `src/supabase.js` helper file to initialize the Supabase client. These variables are exposed
|
||||
on the browser, and that's completely fine since we have [Row Level Security](/docs/guides/auth#row-level-security) enabled on our Database.
|
||||
|
||||
```js title=src/supabase.js
|
||||
```js src/supabase.js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
|
||||
@@ -67,7 +67,7 @@ Optionally, update [src/style.css](https://raw.githubusercontent.com/supabase/su
|
||||
|
||||
Set up an `src/components/Auth.vue` component to manage logins and sign ups. We'll use Magic Links, so users can sign in with their email without using passwords.
|
||||
|
||||
```vue title=/src/components/Auth.vue
|
||||
```vue /src/components/Auth.vue
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { supabase } from '../supabase'
|
||||
@@ -119,7 +119,7 @@ const handleLogin = async () => {
|
||||
After a user is signed in we can allow them to edit their profile details and manage their account.
|
||||
Create a new `src/components/Account.vue` component to handle this.
|
||||
|
||||
```vue title=src/components/Account.vue
|
||||
```vue src/components/Account.vue
|
||||
<script setup>
|
||||
import { supabase } from '../supabase'
|
||||
import { onMounted, ref, toRefs } from 'vue'
|
||||
@@ -232,7 +232,7 @@ async function signOut() {
|
||||
|
||||
Now that we have all the components in place, let's update `App.vue`:
|
||||
|
||||
```vue title=src/App.vue
|
||||
```vue src/App.vue
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import Account from './components/Account.vue'
|
||||
@@ -278,7 +278,7 @@ Every Supabase project is configured with [Storage](/docs/guides/storage) for ma
|
||||
|
||||
Create a new `src/components/Avatar.vue` component that allows users to upload profile photos:
|
||||
|
||||
```vue title=src/components/Avatar.vue
|
||||
```vue src/components/Avatar.vue
|
||||
<script setup>
|
||||
import { ref, toRefs, watch } from 'vue'
|
||||
import { supabase } from '../supabase'
|
||||
@@ -362,7 +362,7 @@ watch(path, () => {
|
||||
|
||||
And then we can add the widget to the Account page in `src/components/Account.vue`:
|
||||
|
||||
```vue title=src/components/Account.vue
|
||||
```vue src/components/Account.vue
|
||||
<script>
|
||||
// Import the new component
|
||||
import Avatar from './Avatar.vue'
|
||||
|
||||
@@ -63,7 +63,7 @@ After that, follow the instructions [here](https://documentation.onesignal.com/d
|
||||
|
||||
The Next.js app will have a login form for the user to sign in, and a button that they can press to make an order once they are signed in. Update the `index.tsx` file to the following.
|
||||
|
||||
```tsx title="pages/index.tsx"
|
||||
```tsx pages/index.tsx
|
||||
import { createClient, User } from '@supabase/supabase-js'
|
||||
import type { NextPage } from 'next'
|
||||
import Head from 'next/head'
|
||||
|
||||
@@ -52,7 +52,7 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git
|
||||
1. At the top right of the users list, open the menu (3 dots) and click **Password hash parameters**.
|
||||
1. Copy and save the parameters for `base64_signer_key`, `base64_salt_separator`, `rounds`, and `mem_cost`.
|
||||
|
||||
```bash title=Sample%20password%20hash%20parameters
|
||||
```text Sample
|
||||
hash_config {
|
||||
algorithm: SCRYPT,
|
||||
base64_signer_key: XXXX/XXX+XXXXXXXXXXXXXXXXX+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX==,
|
||||
|
||||
@@ -61,17 +61,17 @@ git clone https://github.com/supabase-community/firebase-to-supabase.git
|
||||
|
||||
You can customize the way your JSON file is written using a [custom hook](#custom-hooks). A common use for this is to "flatten" the JSON file, or to split nested data into separate, related database tables. For example, you could take a Firestore document that looks like this:
|
||||
|
||||
```json title=Firestore%20document
|
||||
```json Firestore
|
||||
[{ "user": "mark", "score": 100, "items": ["hammer", "nail", "glue"] }]
|
||||
```
|
||||
|
||||
And split it into two files (one table for users and one table for items):
|
||||
|
||||
```json title=Users%20table
|
||||
```json Users
|
||||
[{ "user": "mark", "score": 100 }]
|
||||
```
|
||||
|
||||
```json title=Items%20table
|
||||
```json Items
|
||||
[
|
||||
{ "user": "mark", "item": "hammer" },
|
||||
{ "user": "mark", "item": "nail" },
|
||||
@@ -187,14 +187,14 @@ module.exports = (collectionName, doc, recordCounters, writeRecord) => {
|
||||
|
||||
The result is two separate JSON files:
|
||||
|
||||
```json title=users.json
|
||||
```json users.json
|
||||
[
|
||||
{ "uid": "abc123", "name": "mark", "score": 100 },
|
||||
{ "uid": "xyz789", "name": "chuck", "score": 9999999 }
|
||||
]
|
||||
```
|
||||
|
||||
```json title=weapons.json
|
||||
```json weapons.json
|
||||
[
|
||||
{ "uid": "abc123", "weapon": "toothpick" },
|
||||
{ "uid": "abc123", "weapon": "needle" },
|
||||
|
||||
@@ -88,7 +88,7 @@ We strongly recommend [decoupling your database](../self-hosting#managing-your-d
|
||||
The middleware will run with any PostgreSQL database that has logical replication enabled. The following environment variables should be updated
|
||||
in the `.env` file to point to your external database:
|
||||
|
||||
```env title=.env
|
||||
```bash .env
|
||||
POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password
|
||||
|
||||
POSTGRES_HOST=db
|
||||
|
||||
@@ -1,3 +1,61 @@
|
||||
.dark {
|
||||
--ch-0: dark;
|
||||
--ch-1: #8b949e;
|
||||
--ch-2: #79c0ff;
|
||||
--ch-3: #ffcda1;
|
||||
--ch-4: #f8f8f2;
|
||||
--ch-5: #bda4ff;
|
||||
--ch-6: var(--colors-brand10);
|
||||
--ch-7: #569cd6;
|
||||
--ch-8: var(--colors-brand9);
|
||||
--ch-9: #ffa198;
|
||||
--ch-10: #f0f6fc;
|
||||
--ch-11: #490202;
|
||||
--ch-12: #04260f;
|
||||
--ch-13: #5a1e02;
|
||||
--ch-14: #161b22;
|
||||
--ch-15: #8b949e;
|
||||
--ch-16: var(--colors-scale1);
|
||||
--ch-17: #264f78;
|
||||
--ch-18: #3794ff;
|
||||
--ch-19: #ffffff0b;
|
||||
--ch-20: #6e7681;
|
||||
--ch-21: #010409;
|
||||
--ch-22: #30363d;
|
||||
--ch-23: #f78166;
|
||||
--ch-24: #6e768166;
|
||||
--ch-25: #6e76811a;
|
||||
}
|
||||
|
||||
.light {
|
||||
--ch-0: light;
|
||||
--ch-1: #6e7781;
|
||||
--ch-2: #0550ae;
|
||||
--ch-3: #953800;
|
||||
--ch-4: #24292f;
|
||||
--ch-5: #8250df;
|
||||
--ch-6: var(--colors-brand10);
|
||||
--ch-7: #cf222e;
|
||||
--ch-8: var(--colors-brand9);
|
||||
--ch-9: #82071e;
|
||||
--ch-10: #f6f8fa;
|
||||
--ch-11: #ffebe9;
|
||||
--ch-12: #dafbe1;
|
||||
--ch-13: #ffd8b5;
|
||||
--ch-14: #eaeef2;
|
||||
--ch-15: #57606a;
|
||||
--ch-16: var(--colors-scale1);
|
||||
--ch-17: #add6ff;
|
||||
--ch-18: #1a85ff;
|
||||
--ch-19: #fdff0033;
|
||||
--ch-20: #8c959f;
|
||||
--ch-21: #f6f8fa;
|
||||
--ch-22: #d0d7de;
|
||||
--ch-23: #fd8c73;
|
||||
--ch-24: #afb8c133;
|
||||
--ch-25: #eaeef280;
|
||||
}
|
||||
|
||||
.ch-terminal {
|
||||
font-size: 14px;
|
||||
height: 100%;
|
||||
6
apps/docs/types/code-hike.d.ts
vendored
Normal file
6
apps/docs/types/code-hike.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { remarkCodeHike } from '@code-hike/mdx'
|
||||
|
||||
declare module '@code-hike/mdx' {
|
||||
export type CodeHikeRemarkPlugin = typeof remarkCodeHike
|
||||
export type CodeHikeConfig = Parameters<CodeHikeRemarkPlugin>[0]
|
||||
}
|
||||
82
package-lock.json
generated
82
package-lock.json
generated
@@ -38,6 +38,7 @@
|
||||
"dependencies": {
|
||||
"@algolia/autocomplete-js": "^1.7.2",
|
||||
"@algolia/autocomplete-plugin-recent-searches": "^1.7.2",
|
||||
"@code-hike/mdx": "^0.8.3",
|
||||
"@docsearch/react": "^3.3.0",
|
||||
"@mdx-js/loader": "^1.6.22",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
@@ -3091,6 +3092,31 @@
|
||||
"node": ">=0.1.95"
|
||||
}
|
||||
},
|
||||
"node_modules/@code-hike/lighter": {
|
||||
"version": "0.6.7",
|
||||
"resolved": "https://registry.npmjs.org/@code-hike/lighter/-/lighter-0.6.7.tgz",
|
||||
"integrity": "sha512-NJJ/s5IdemXHf+D6RsCm+eCYPI5BKmJE1yL2+euKFhY5mLhYt3yljHF7ly7E0pu7R9QrY2y0spGLL+SFUOgz6g==",
|
||||
"funding": {
|
||||
"url": "https://github.com/code-hike/lighter?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@code-hike/mdx": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@code-hike/mdx/-/mdx-0.8.3.tgz",
|
||||
"integrity": "sha512-pbbv7PivrU+GqPiM0ufehNyhsoge8V25fx+y89M2yKgEWMAFnNkk4E1XaW/X81QzIq3h58IoKEWnNYSJpERTvA==",
|
||||
"dependencies": {
|
||||
"@code-hike/lighter": "0.6.4",
|
||||
"node-fetch": "^2.0.0",
|
||||
"shiki": "^0.10.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/code-hike"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.3 || ^17 || ^18"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/language": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.0.0.tgz",
|
||||
@@ -40559,6 +40585,16 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/shiki": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz",
|
||||
"integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==",
|
||||
"dependencies": {
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"vscode-oniguruma": "^1.6.1",
|
||||
"vscode-textmate": "5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
@@ -44293,6 +44329,16 @@
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz",
|
||||
"integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA=="
|
||||
},
|
||||
"node_modules/vscode-oniguruma": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
|
||||
"integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA=="
|
||||
},
|
||||
"node_modules/vscode-textmate": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz",
|
||||
"integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ=="
|
||||
},
|
||||
"node_modules/w3c-hr-time": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
||||
@@ -48826,6 +48872,21 @@
|
||||
"minimist": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@code-hike/lighter": {
|
||||
"version": "0.6.7",
|
||||
"resolved": "https://registry.npmjs.org/@code-hike/lighter/-/lighter-0.6.7.tgz",
|
||||
"integrity": "sha512-NJJ/s5IdemXHf+D6RsCm+eCYPI5BKmJE1yL2+euKFhY5mLhYt3yljHF7ly7E0pu7R9QrY2y0spGLL+SFUOgz6g=="
|
||||
},
|
||||
"@code-hike/mdx": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@code-hike/mdx/-/mdx-0.8.3.tgz",
|
||||
"integrity": "sha512-pbbv7PivrU+GqPiM0ufehNyhsoge8V25fx+y89M2yKgEWMAFnNkk4E1XaW/X81QzIq3h58IoKEWnNYSJpERTvA==",
|
||||
"requires": {
|
||||
"@code-hike/lighter": "^0.6.7",
|
||||
"node-fetch": "^2.0.0",
|
||||
"shiki": "^0.10.1"
|
||||
}
|
||||
},
|
||||
"@codemirror/language": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.0.0.tgz",
|
||||
@@ -62954,6 +63015,7 @@
|
||||
"requires": {
|
||||
"@algolia/autocomplete-js": "^1.7.2",
|
||||
"@algolia/autocomplete-plugin-recent-searches": "^1.7.2",
|
||||
"@code-hike/mdx": "^0.8.3",
|
||||
"@docsearch/react": "^3.3.0",
|
||||
"@mdx-js/loader": "^1.6.22",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
@@ -77788,6 +77850,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"shiki": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz",
|
||||
"integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==",
|
||||
"requires": {
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"vscode-oniguruma": "^1.6.1",
|
||||
"vscode-textmate": "5.2.0"
|
||||
}
|
||||
},
|
||||
"side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
@@ -81728,6 +81800,16 @@
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz",
|
||||
"integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA=="
|
||||
},
|
||||
"vscode-oniguruma": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
|
||||
"integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA=="
|
||||
},
|
||||
"vscode-textmate": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz",
|
||||
"integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ=="
|
||||
},
|
||||
"w3c-hr-time": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
||||
|
||||
@@ -33,6 +33,11 @@
|
||||
"perf:meta": "ab -t 5 -c 20 -T application/json http://localhost:5555/tables",
|
||||
"generate:types": "supabase gen types typescript --local > ./supabase/functions/common/database-types.ts"
|
||||
},
|
||||
"overrides": {
|
||||
"@code-hike/mdx": {
|
||||
"@code-hike/lighter": "^0.6.7"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/json-stringify-safe": "^5.0.0",
|
||||
"aws-sdk": "^2.1354.0",
|
||||
|
||||
Reference in New Issue
Block a user