Updating to TofuStack formatting of APIs with old version for starting the hono service. Getting scaffolding for signup with username/email set up.

This commit is contained in:
Bradley Shellnut 2025-01-01 18:27:43 -08:00
parent 2c2f33ea68
commit 64f0e10715
410 changed files with 11048 additions and 10240 deletions

549
.editorconfig Normal file
View file

@ -0,0 +1,549 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = tab
insert_final_newline = false
max_line_length = 120
tab_width = 2
ij_continuation_indent_size = 4
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = false
ij_smart_tabs = false
ij_visual_guides = none
ij_wrap_on_typing = false
[*.css]
ij_css_align_closing_brace_with_properties = false
ij_css_blank_lines_around_nested_selector = 1
ij_css_blank_lines_between_blocks = 1
ij_css_block_comment_add_space = false
ij_css_brace_placement = end_of_line
ij_css_enforce_quotes_on_format = false
ij_css_hex_color_long_format = false
ij_css_hex_color_lower_case = false
ij_css_hex_color_short_format = false
ij_css_hex_color_upper_case = false
ij_css_keep_blank_lines_in_code = 2
ij_css_keep_indents_on_empty_lines = false
ij_css_keep_single_line_blocks = false
ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_css_space_after_colon = true
ij_css_space_before_opening_brace = true
ij_css_use_double_quotes = true
ij_css_value_alignment = do_not_align
[*.less]
ij_less_align_closing_brace_with_properties = false
ij_less_blank_lines_around_nested_selector = 1
ij_less_blank_lines_between_blocks = 1
ij_less_block_comment_add_space = false
ij_less_brace_placement = 0
ij_less_enforce_quotes_on_format = false
ij_less_hex_color_long_format = false
ij_less_hex_color_lower_case = false
ij_less_hex_color_short_format = false
ij_less_hex_color_upper_case = false
ij_less_keep_blank_lines_in_code = 2
ij_less_keep_indents_on_empty_lines = false
ij_less_keep_single_line_blocks = false
ij_less_line_comment_add_space = false
ij_less_line_comment_at_first_column = false
ij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_less_space_after_colon = true
ij_less_space_before_opening_brace = true
ij_less_use_double_quotes = true
ij_less_value_alignment = 0
[*.sass]
ij_sass_align_closing_brace_with_properties = false
ij_sass_blank_lines_around_nested_selector = 1
ij_sass_blank_lines_between_blocks = 1
ij_sass_brace_placement = 0
ij_sass_enforce_quotes_on_format = false
ij_sass_hex_color_long_format = false
ij_sass_hex_color_lower_case = false
ij_sass_hex_color_short_format = false
ij_sass_hex_color_upper_case = false
ij_sass_keep_blank_lines_in_code = 2
ij_sass_keep_indents_on_empty_lines = false
ij_sass_keep_single_line_blocks = false
ij_sass_line_comment_add_space = false
ij_sass_line_comment_at_first_column = false
ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_sass_space_after_colon = true
ij_sass_space_before_opening_brace = true
ij_sass_use_double_quotes = true
ij_sass_value_alignment = 0
[*.scss]
ij_scss_align_closing_brace_with_properties = false
ij_scss_blank_lines_around_nested_selector = 1
ij_scss_blank_lines_between_blocks = 1
ij_scss_block_comment_add_space = false
ij_scss_brace_placement = 0
ij_scss_enforce_quotes_on_format = false
ij_scss_hex_color_long_format = false
ij_scss_hex_color_lower_case = false
ij_scss_hex_color_short_format = false
ij_scss_hex_color_upper_case = false
ij_scss_keep_blank_lines_in_code = 2
ij_scss_keep_indents_on_empty_lines = false
ij_scss_keep_single_line_blocks = false
ij_scss_line_comment_add_space = false
ij_scss_line_comment_at_first_column = false
ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_scss_space_after_colon = true
ij_scss_space_before_opening_brace = true
ij_scss_use_double_quotes = true
ij_scss_value_alignment = 0
[.editorconfig]
ij_editorconfig_align_group_field_declarations = false
ij_editorconfig_space_after_colon = false
ij_editorconfig_space_after_comma = true
ij_editorconfig_space_before_colon = false
ij_editorconfig_space_before_comma = false
ij_editorconfig_spaces_around_assignment_operators = true
[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.pom,*.rng,*.tld,*.wadl,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}]
ij_xml_align_attributes = true
ij_xml_align_text = false
ij_xml_attribute_wrap = normal
ij_xml_block_comment_add_space = false
ij_xml_block_comment_at_first_column = true
ij_xml_keep_blank_lines = 2
ij_xml_keep_indents_on_empty_lines = false
ij_xml_keep_line_breaks = true
ij_xml_keep_line_breaks_in_text = true
ij_xml_keep_whitespaces = false
ij_xml_keep_whitespaces_around_cdata = preserve
ij_xml_keep_whitespaces_inside_cdata = false
ij_xml_line_comment_at_first_column = true
ij_xml_space_after_tag_name = false
ij_xml_space_around_equals_in_attribute = false
ij_xml_space_inside_empty_tag = false
ij_xml_text_wrap = normal
ij_xml_use_custom_settings = false
[{*.ats,*.cts,*.mts,*.ts}]
ij_typescript_align_imports = false
ij_typescript_align_multiline_array_initializer_expression = false
ij_typescript_align_multiline_binary_operation = false
ij_typescript_align_multiline_chained_methods = false
ij_typescript_align_multiline_extends_list = false
ij_typescript_align_multiline_for = true
ij_typescript_align_multiline_parameters = true
ij_typescript_align_multiline_parameters_in_calls = false
ij_typescript_align_multiline_ternary_operation = false
ij_typescript_align_object_properties = 0
ij_typescript_align_union_types = false
ij_typescript_align_var_statements = 0
ij_typescript_array_initializer_new_line_after_left_brace = false
ij_typescript_array_initializer_right_brace_on_new_line = false
ij_typescript_array_initializer_wrap = off
ij_typescript_assignment_wrap = off
ij_typescript_binary_operation_sign_on_next_line = false
ij_typescript_binary_operation_wrap = off
ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
ij_typescript_blank_lines_after_imports = 1
ij_typescript_blank_lines_around_class = 1
ij_typescript_blank_lines_around_field = 0
ij_typescript_blank_lines_around_field_in_interface = 0
ij_typescript_blank_lines_around_function = 1
ij_typescript_blank_lines_around_method = 1
ij_typescript_blank_lines_around_method_in_interface = 1
ij_typescript_block_brace_style = end_of_line
ij_typescript_block_comment_add_space = false
ij_typescript_block_comment_at_first_column = true
ij_typescript_call_parameters_new_line_after_left_paren = false
ij_typescript_call_parameters_right_paren_on_new_line = false
ij_typescript_call_parameters_wrap = off
ij_typescript_catch_on_new_line = false
ij_typescript_chained_call_dot_on_new_line = true
ij_typescript_class_brace_style = end_of_line
ij_typescript_comma_on_new_line = false
ij_typescript_do_while_brace_force = never
ij_typescript_else_on_new_line = false
ij_typescript_enforce_trailing_comma = keep
ij_typescript_enum_constants_wrap = on_every_item
ij_typescript_extends_keyword_wrap = off
ij_typescript_extends_list_wrap = off
ij_typescript_field_prefix = _
ij_typescript_file_name_style = relaxed
ij_typescript_finally_on_new_line = false
ij_typescript_for_brace_force = never
ij_typescript_for_statement_new_line_after_left_paren = false
ij_typescript_for_statement_right_paren_on_new_line = false
ij_typescript_for_statement_wrap = off
ij_typescript_force_quote_style = false
ij_typescript_force_semicolon_style = false
ij_typescript_function_expression_brace_style = end_of_line
ij_typescript_if_brace_force = never
ij_typescript_import_merge_members = global
ij_typescript_import_prefer_absolute_path = global
ij_typescript_import_sort_members = true
ij_typescript_import_sort_module_name = false
ij_typescript_import_use_node_resolution = true
ij_typescript_imports_wrap = on_every_item
ij_typescript_indent_case_from_switch = true
ij_typescript_indent_chained_calls = true
ij_typescript_indent_package_children = 0
ij_typescript_jsdoc_include_types = false
ij_typescript_jsx_attribute_value = braces
ij_typescript_keep_blank_lines_in_code = 2
ij_typescript_keep_first_column_comment = true
ij_typescript_keep_indents_on_empty_lines = false
ij_typescript_keep_line_breaks = true
ij_typescript_keep_simple_blocks_in_one_line = false
ij_typescript_keep_simple_methods_in_one_line = false
ij_typescript_line_comment_add_space = true
ij_typescript_line_comment_at_first_column = false
ij_typescript_method_brace_style = end_of_line
ij_typescript_method_call_chain_wrap = off
ij_typescript_method_parameters_new_line_after_left_paren = false
ij_typescript_method_parameters_right_paren_on_new_line = false
ij_typescript_method_parameters_wrap = off
ij_typescript_object_literal_wrap = on_every_item
ij_typescript_parentheses_expression_new_line_after_left_paren = false
ij_typescript_parentheses_expression_right_paren_on_new_line = false
ij_typescript_place_assignment_sign_on_next_line = false
ij_typescript_prefer_as_type_cast = false
ij_typescript_prefer_explicit_types_function_expression_returns = false
ij_typescript_prefer_explicit_types_function_returns = false
ij_typescript_prefer_explicit_types_vars_fields = false
ij_typescript_prefer_parameters_wrap = false
ij_typescript_reformat_c_style_comments = false
ij_typescript_space_after_colon = true
ij_typescript_space_after_comma = true
ij_typescript_space_after_dots_in_rest_parameter = false
ij_typescript_space_after_generator_mult = true
ij_typescript_space_after_property_colon = true
ij_typescript_space_after_quest = true
ij_typescript_space_after_type_colon = true
ij_typescript_space_after_unary_not = false
ij_typescript_space_before_async_arrow_lparen = true
ij_typescript_space_before_catch_keyword = true
ij_typescript_space_before_catch_left_brace = true
ij_typescript_space_before_catch_parentheses = true
ij_typescript_space_before_class_lbrace = true
ij_typescript_space_before_class_left_brace = true
ij_typescript_space_before_colon = true
ij_typescript_space_before_comma = false
ij_typescript_space_before_do_left_brace = true
ij_typescript_space_before_else_keyword = true
ij_typescript_space_before_else_left_brace = true
ij_typescript_space_before_finally_keyword = true
ij_typescript_space_before_finally_left_brace = true
ij_typescript_space_before_for_left_brace = true
ij_typescript_space_before_for_parentheses = true
ij_typescript_space_before_for_semicolon = false
ij_typescript_space_before_function_left_parenth = true
ij_typescript_space_before_generator_mult = false
ij_typescript_space_before_if_left_brace = true
ij_typescript_space_before_if_parentheses = true
ij_typescript_space_before_method_call_parentheses = false
ij_typescript_space_before_method_left_brace = true
ij_typescript_space_before_method_parentheses = false
ij_typescript_space_before_property_colon = false
ij_typescript_space_before_quest = true
ij_typescript_space_before_switch_left_brace = true
ij_typescript_space_before_switch_parentheses = true
ij_typescript_space_before_try_left_brace = true
ij_typescript_space_before_type_colon = false
ij_typescript_space_before_unary_not = false
ij_typescript_space_before_while_keyword = true
ij_typescript_space_before_while_left_brace = true
ij_typescript_space_before_while_parentheses = true
ij_typescript_spaces_around_additive_operators = true
ij_typescript_spaces_around_arrow_function_operator = true
ij_typescript_spaces_around_assignment_operators = true
ij_typescript_spaces_around_bitwise_operators = true
ij_typescript_spaces_around_equality_operators = true
ij_typescript_spaces_around_logical_operators = true
ij_typescript_spaces_around_multiplicative_operators = true
ij_typescript_spaces_around_relational_operators = true
ij_typescript_spaces_around_shift_operators = true
ij_typescript_spaces_around_unary_operator = false
ij_typescript_spaces_within_array_initializer_brackets = false
ij_typescript_spaces_within_brackets = false
ij_typescript_spaces_within_catch_parentheses = false
ij_typescript_spaces_within_for_parentheses = false
ij_typescript_spaces_within_if_parentheses = false
ij_typescript_spaces_within_imports = false
ij_typescript_spaces_within_interpolation_expressions = false
ij_typescript_spaces_within_method_call_parentheses = false
ij_typescript_spaces_within_method_parentheses = false
ij_typescript_spaces_within_object_literal_braces = false
ij_typescript_spaces_within_object_type_braces = true
ij_typescript_spaces_within_parentheses = false
ij_typescript_spaces_within_switch_parentheses = false
ij_typescript_spaces_within_type_assertion = false
ij_typescript_spaces_within_union_types = true
ij_typescript_spaces_within_while_parentheses = false
ij_typescript_special_else_if_treatment = true
ij_typescript_ternary_operation_signs_on_next_line = false
ij_typescript_ternary_operation_wrap = off
ij_typescript_union_types_wrap = on_every_item
ij_typescript_use_chained_calls_group_indents = false
ij_typescript_use_double_quotes = true
ij_typescript_use_explicit_js_extension = auto
ij_typescript_use_path_mapping = always
ij_typescript_use_public_modifier = false
ij_typescript_use_semicolon_after_statement = true
ij_typescript_var_declaration_wrap = normal
ij_typescript_while_brace_force = never
ij_typescript_while_on_new_line = false
ij_typescript_wrap_comments = false
[{*.cjs,*.js}]
ij_javascript_align_imports = false
ij_javascript_align_multiline_array_initializer_expression = false
ij_javascript_align_multiline_binary_operation = false
ij_javascript_align_multiline_chained_methods = false
ij_javascript_align_multiline_extends_list = false
ij_javascript_align_multiline_for = true
ij_javascript_align_multiline_parameters = true
ij_javascript_align_multiline_parameters_in_calls = false
ij_javascript_align_multiline_ternary_operation = false
ij_javascript_align_object_properties = 0
ij_javascript_align_union_types = false
ij_javascript_align_var_statements = 0
ij_javascript_array_initializer_new_line_after_left_brace = false
ij_javascript_array_initializer_right_brace_on_new_line = false
ij_javascript_array_initializer_wrap = off
ij_javascript_assignment_wrap = off
ij_javascript_binary_operation_sign_on_next_line = false
ij_javascript_binary_operation_wrap = off
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
ij_javascript_blank_lines_after_imports = 1
ij_javascript_blank_lines_around_class = 1
ij_javascript_blank_lines_around_field = 0
ij_javascript_blank_lines_around_function = 1
ij_javascript_blank_lines_around_method = 1
ij_javascript_block_brace_style = end_of_line
ij_javascript_block_comment_add_space = false
ij_javascript_block_comment_at_first_column = true
ij_javascript_call_parameters_new_line_after_left_paren = false
ij_javascript_call_parameters_right_paren_on_new_line = false
ij_javascript_call_parameters_wrap = off
ij_javascript_catch_on_new_line = false
ij_javascript_chained_call_dot_on_new_line = true
ij_javascript_class_brace_style = end_of_line
ij_javascript_comma_on_new_line = false
ij_javascript_do_while_brace_force = never
ij_javascript_else_on_new_line = false
ij_javascript_enforce_trailing_comma = keep
ij_javascript_extends_keyword_wrap = off
ij_javascript_extends_list_wrap = off
ij_javascript_field_prefix = _
ij_javascript_file_name_style = relaxed
ij_javascript_finally_on_new_line = false
ij_javascript_for_brace_force = never
ij_javascript_for_statement_new_line_after_left_paren = false
ij_javascript_for_statement_right_paren_on_new_line = false
ij_javascript_for_statement_wrap = off
ij_javascript_force_quote_style = false
ij_javascript_force_semicolon_style = false
ij_javascript_function_expression_brace_style = end_of_line
ij_javascript_if_brace_force = never
ij_javascript_import_merge_members = global
ij_javascript_import_prefer_absolute_path = global
ij_javascript_import_sort_members = true
ij_javascript_import_sort_module_name = false
ij_javascript_import_use_node_resolution = true
ij_javascript_imports_wrap = on_every_item
ij_javascript_indent_case_from_switch = true
ij_javascript_indent_chained_calls = true
ij_javascript_indent_package_children = 0
ij_javascript_jsx_attribute_value = braces
ij_javascript_keep_blank_lines_in_code = 2
ij_javascript_keep_first_column_comment = true
ij_javascript_keep_indents_on_empty_lines = false
ij_javascript_keep_line_breaks = true
ij_javascript_keep_simple_blocks_in_one_line = false
ij_javascript_keep_simple_methods_in_one_line = false
ij_javascript_line_comment_add_space = true
ij_javascript_line_comment_at_first_column = false
ij_javascript_method_brace_style = end_of_line
ij_javascript_method_call_chain_wrap = off
ij_javascript_method_parameters_new_line_after_left_paren = false
ij_javascript_method_parameters_right_paren_on_new_line = false
ij_javascript_method_parameters_wrap = off
ij_javascript_object_literal_wrap = on_every_item
ij_javascript_parentheses_expression_new_line_after_left_paren = false
ij_javascript_parentheses_expression_right_paren_on_new_line = false
ij_javascript_place_assignment_sign_on_next_line = false
ij_javascript_prefer_as_type_cast = false
ij_javascript_prefer_explicit_types_function_expression_returns = false
ij_javascript_prefer_explicit_types_function_returns = false
ij_javascript_prefer_explicit_types_vars_fields = false
ij_javascript_prefer_parameters_wrap = false
ij_javascript_reformat_c_style_comments = false
ij_javascript_space_after_colon = true
ij_javascript_space_after_comma = true
ij_javascript_space_after_dots_in_rest_parameter = false
ij_javascript_space_after_generator_mult = true
ij_javascript_space_after_property_colon = true
ij_javascript_space_after_quest = true
ij_javascript_space_after_type_colon = true
ij_javascript_space_after_unary_not = false
ij_javascript_space_before_async_arrow_lparen = true
ij_javascript_space_before_catch_keyword = true
ij_javascript_space_before_catch_left_brace = true
ij_javascript_space_before_catch_parentheses = true
ij_javascript_space_before_class_lbrace = true
ij_javascript_space_before_class_left_brace = true
ij_javascript_space_before_colon = true
ij_javascript_space_before_comma = false
ij_javascript_space_before_do_left_brace = true
ij_javascript_space_before_else_keyword = true
ij_javascript_space_before_else_left_brace = true
ij_javascript_space_before_finally_keyword = true
ij_javascript_space_before_finally_left_brace = true
ij_javascript_space_before_for_left_brace = true
ij_javascript_space_before_for_parentheses = true
ij_javascript_space_before_for_semicolon = false
ij_javascript_space_before_function_left_parenth = true
ij_javascript_space_before_generator_mult = false
ij_javascript_space_before_if_left_brace = true
ij_javascript_space_before_if_parentheses = true
ij_javascript_space_before_method_call_parentheses = false
ij_javascript_space_before_method_left_brace = true
ij_javascript_space_before_method_parentheses = false
ij_javascript_space_before_property_colon = false
ij_javascript_space_before_quest = true
ij_javascript_space_before_switch_left_brace = true
ij_javascript_space_before_switch_parentheses = true
ij_javascript_space_before_try_left_brace = true
ij_javascript_space_before_type_colon = false
ij_javascript_space_before_unary_not = false
ij_javascript_space_before_while_keyword = true
ij_javascript_space_before_while_left_brace = true
ij_javascript_space_before_while_parentheses = true
ij_javascript_spaces_around_additive_operators = true
ij_javascript_spaces_around_arrow_function_operator = true
ij_javascript_spaces_around_assignment_operators = true
ij_javascript_spaces_around_bitwise_operators = true
ij_javascript_spaces_around_equality_operators = true
ij_javascript_spaces_around_logical_operators = true
ij_javascript_spaces_around_multiplicative_operators = true
ij_javascript_spaces_around_relational_operators = true
ij_javascript_spaces_around_shift_operators = true
ij_javascript_spaces_around_unary_operator = false
ij_javascript_spaces_within_array_initializer_brackets = false
ij_javascript_spaces_within_brackets = false
ij_javascript_spaces_within_catch_parentheses = false
ij_javascript_spaces_within_for_parentheses = false
ij_javascript_spaces_within_if_parentheses = false
ij_javascript_spaces_within_imports = false
ij_javascript_spaces_within_interpolation_expressions = false
ij_javascript_spaces_within_method_call_parentheses = false
ij_javascript_spaces_within_method_parentheses = false
ij_javascript_spaces_within_object_literal_braces = false
ij_javascript_spaces_within_object_type_braces = true
ij_javascript_spaces_within_parentheses = false
ij_javascript_spaces_within_switch_parentheses = false
ij_javascript_spaces_within_type_assertion = false
ij_javascript_spaces_within_union_types = true
ij_javascript_spaces_within_while_parentheses = false
ij_javascript_special_else_if_treatment = true
ij_javascript_ternary_operation_signs_on_next_line = false
ij_javascript_ternary_operation_wrap = off
ij_javascript_union_types_wrap = on_every_item
ij_javascript_use_chained_calls_group_indents = false
ij_javascript_use_double_quotes = true
ij_javascript_use_explicit_js_extension = auto
ij_javascript_use_path_mapping = always
ij_javascript_use_public_modifier = false
ij_javascript_use_semicolon_after_statement = true
ij_javascript_var_declaration_wrap = normal
ij_javascript_while_brace_force = never
ij_javascript_while_on_new_line = false
ij_javascript_wrap_comments = false
[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}]
ij_json_array_wrapping = split_into_lines
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_keep_trailing_comma = false
ij_json_object_wrapping = split_into_lines
ij_json_property_alignment = do_not_align
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = false
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}]
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
ij_html_align_attributes = true
ij_html_align_text = false
ij_html_attribute_wrap = normal
ij_html_block_comment_add_space = false
ij_html_block_comment_at_first_column = true
ij_html_do_not_align_children_of_min_lines = 0
ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p
ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot
ij_html_enforce_quotes = false
ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var
ij_html_keep_blank_lines = 2
ij_html_keep_indents_on_empty_lines = false
ij_html_keep_line_breaks = true
ij_html_keep_line_breaks_in_text = true
ij_html_keep_whitespaces = false
ij_html_keep_whitespaces_inside = span,pre,textarea
ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never
ij_html_quote_style = double
ij_html_remove_new_line_before_tags = br
ij_html_space_after_tag_name = false
ij_html_space_around_equality_in_attribute = false
ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal
[{*.markdown,*.md}]
ij_markdown_force_one_space_after_blockquote_symbol = true
ij_markdown_force_one_space_after_header_symbol = true
ij_markdown_force_one_space_after_list_bullet = true
ij_markdown_force_one_space_between_words = true
ij_markdown_format_tables = true
ij_markdown_insert_quote_arrows_on_wrap = true
ij_markdown_keep_indents_on_empty_lines = false
ij_markdown_keep_line_breaks_inside_text_blocks = true
ij_markdown_max_lines_around_block_elements = 1
ij_markdown_max_lines_around_header = 1
ij_markdown_max_lines_between_paragraphs = 1
ij_markdown_min_lines_around_block_elements = 1
ij_markdown_min_lines_around_header = 1
ij_markdown_min_lines_between_paragraphs = 1
ij_markdown_wrap_text_if_long = true
ij_markdown_wrap_text_inside_blockquotes = true
[{*.properties,spring.handlers,spring.schemas}]
ij_properties_align_group_field_declarations = false
ij_properties_keep_blank_lines = false
ij_properties_key_value_delimiter = equals
ij_properties_spaces_around_key_value_delimiter = false
[{*.toml,Cargo.lock,Cargo.toml.orig,Gopkg.lock,Pipfile,poetry.lock}]
ij_toml_keep_indents_on_empty_lines = false
[{*.yaml,*.yml}]
ij_yaml_align_values_properties = do_not_align
ij_yaml_autoinsert_sequence_marker = true
ij_yaml_block_mapping_on_new_line = false
ij_yaml_indent_sequence_value = true
ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true
ij_yaml_sequence_on_new_line = false
ij_yaml_space_before_colon = false
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true

View file

@ -1,15 +1,45 @@
# Environment
ENV=dev
# API # API
ORIGIN=http://localhost:5173 ORIGIN=http://localhost:5173
DOMAIN=localhost
PORT=5173
# Database # Database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres DATABASE_USER='postgres'
DATABASE_PASSWORD='postgres'
DATABASE_HOST='localhost'
DATABASE_PORT=5432
DATABASE_DB='postgres'
# Drizzle
LOG_LEVEL=debug
DB_MIGRATING=false
DB_SEEDING=false
ADMIN_USERNAME=
ADMIN_PASSWORD=
# Redis # Redis
REDIS_URL=redis://localhost:6379 REDIS_URL=redis://localhost:6379
# Security - openssl rand -hex 32
SIGNING_SECRET=
# Storage # Storage
PUBLIC_IMAGE_URI=http://localhost:9000/dev PUBLIC_IMAGE_URI=http://localhost:9000/dev
STORAGE_BUCKET=dev STORAGE_BUCKET=dev
STORAGE_URL=http://localhost:9000 STORAGE_URL=http://localhost:9000
STORAGE_ACCESS_KEY=user STORAGE_ACCESS_KEY=user
STORAGE_SECRET_KEY=password STORAGE_SECRET_KEY=password
# Public
PUBLIC_SITE_NAME=
PUBLIC_SITE_URL='http://$DOMAIN:5173'
# Public Analytics
PUBLIC_UMAMI_URL=""
PUBLIC_UMAMI_ID=""
# quick setting for key-combo only
SVELTE_INSPECTOR_TOGGLE=control-shift-i

View file

@ -1,13 +0,0 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

23
.gitignore vendored
View file

@ -1,10 +1,27 @@
.DS_Store test-results
node_modules node_modules
/build
# Output
.output
.vercel
.netlify
.wrangler
/.svelte-kit /.svelte-kit
/package /build
# OS
.DS_Store
Thumbs.db
# Env
.env .env
.env.* .env.*
!.env.example !.env.example
!.env.test
# Vite
vite.config.js.timestamp-* vite.config.js.timestamp-*
vite.config.ts.timestamp-* vite.config.ts.timestamp-*
# Paraglide
src/lib/paraglide

View file

@ -1 +0,0 @@
22.1.0

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
22

View file

@ -1,4 +0,0 @@
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

View file

@ -1,8 +0,0 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

15
.storybook/main.js Normal file
View file

@ -0,0 +1,15 @@
/** @type { import('@storybook/sveltekit').StorybookConfig } */
const config = {
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|ts|svelte)"],
addons: [
"@storybook/addon-svelte-csf",
"@storybook/addon-essentials",
"@chromatic-com/storybook",
"@storybook/addon-interactions",
],
framework: {
name: "@storybook/sveltekit",
options: {},
},
};
export default config;

13
.storybook/preview.js Normal file
View file

@ -0,0 +1,13 @@
/** @type { import('@storybook/svelte').Preview } */
const preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};
export default preview;

65
biome.json Normal file
View file

@ -0,0 +1,65 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": { "ignoreUnknown": false, "ignore": [] },
"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 150,
"attributePosition": "auto",
"ignore": [
"**/.DS_Store",
"**/node_modules",
"./build",
"./.svelte-kit",
"./package",
"**/.env",
"**/.env.*",
"**/pnpm-lock.yaml",
"**/package-lock.json",
"**/yarn.lock",
"**/paraglide/**"
]
},
"organizeImports": { "enabled": true },
"linter": { "enabled": true, "rules": { "recommended": true } },
"javascript": {
"formatter": {
"jsxQuoteStyle": "single",
"quoteProperties": "asNeeded",
"trailingCommas": "all",
"indentStyle": "space",
"lineEnding": "lf",
"lineWidth": 150,
"semicolons": "always",
"arrowParentheses": "always",
"bracketSpacing": true,
"bracketSameLine": false,
"quoteStyle": "single",
"attributePosition": "auto"
},
"parser": {
"unsafeParameterDecoratorsEnabled": true
}
},
"overrides": [
{
"include": ["*.svelte"],
"linter": {
"rules": {
"style": {
"useConst": "off",
"useImportType": "off"
}
}
}
}
]
}

View file

@ -1,5 +1,5 @@
{ {
"$schema": "https://shadcn-svelte.com/schema.json", "$schema": "https://next.shadcn-svelte.com/schema.json",
"style": "default", "style": "default",
"tailwind": { "tailwind": {
"config": "tailwind.config.ts", "config": "tailwind.config.ts",
@ -8,7 +8,10 @@
}, },
"aliases": { "aliases": {
"components": "$lib/components", "components": "$lib/components",
"utils": "$lib/utils/ui" "utils": "$lib/utils",
"ui": "$lib/components/ui",
"hooks": "$lib/hooks"
}, },
"typescript": true "typescript": true,
"registry": "https://next.shadcn-svelte.com/registry"
} }

View file

@ -1,40 +1,43 @@
version: '3.8' version: "3.8"
services: services:
postgres: postgres:
image: postgres:latest image: postgres:latest
container_name: tofu_postgres
environment: environment:
POSTGRES_USER: postgres POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres POSTGRES_DB: postgres
ports: ports:
- '5432:5432' - "5432:5432"
volumes: volumes:
- postgres_data:/data - postgres_data:/data
networks:
- app-network
redis: redis:
image: redis:latest image: redis:latest
container_name: tofu_redis
ports: ports:
- '6379:6379' - "6379:6379"
volumes: volumes:
- redis_data:/data - redis_data:/data
networks:
- app-network
minio: minio:
image: docker.io/bitnami/minio image: docker.io/bitnami/minio
container_name: tofu_minio
ports: ports:
- '9000:9000' - "9000:9000"
- '9001:9001' - "9001:9001"
networks: networks:
- minionetwork - app-network
volumes: volumes:
- 'minio_data:/data' - "minio_data:/data"
environment: environment:
- MINIO_ROOT_USER=user - MINIO_ROOT_USER=user
- MINIO_ROOT_PASSWORD=password - MINIO_ROOT_PASSWORD=password
- MINIO_DEFAULT_BUCKETS=dev - MINIO_DEFAULT_BUCKETS=dev
mailpit: mailpit:
image: axllent/mailpit image: axllent/mailpit
container_name: tofu_mailpit
volumes: volumes:
- mailpit_data:/data - mailpit_data:/data
ports: ports:
@ -45,6 +48,8 @@ services:
MP_DATABASE: /data/mailpit.db MP_DATABASE: /data/mailpit.db
MP_SMTP_AUTH_ACCEPT_ANY: 1 MP_SMTP_AUTH_ACCEPT_ANY: 1
MP_SMTP_AUTH_ALLOW_INSECURE: 1 MP_SMTP_AUTH_ALLOW_INSECURE: 1
networks:
- app-network
volumes: volumes:
postgres_data: postgres_data:
@ -54,5 +59,5 @@ volumes:
driver: local driver: local
networks: networks:
minionetwork: app-network:
driver: bridge driver: bridge

6
e2e/demo.test.ts Normal file
View file

@ -0,0 +1,6 @@
import { expect, test } from '@playwright/test';
test('home page has expected h1', async ({ page }) => {
await page.goto('/');
await expect(page.locator('h1')).toBeVisible();
});

View file

@ -1,33 +0,0 @@
import js from '@eslint/js';
import ts from 'typescript-eslint';
import svelte from 'eslint-plugin-svelte';
import prettier from 'eslint-config-prettier';
import globals from 'globals';
/** @type {import('eslint').Linter.FlatConfig[]} */
export default [
js.configs.recommended,
...ts.configs.recommended,
...svelte.configs['flat/recommended'],
prettier,
...svelte.configs['flat/prettier'],
{
languageOptions: {
globals: {
...globals.browser,
...globals.node
}
}
},
{
files: ['**/*.svelte'],
languageOptions: {
parserOptions: {
parser: ts.parser
}
}
},
{
ignores: ['build/', '.svelte-kit/', 'dist/']
}
];

4
messages/en.json Normal file
View file

@ -0,0 +1,4 @@
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"hello_world": "Hello, {name} from en!"
}

4
messages/es.json Normal file
View file

@ -0,0 +1,4 @@
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"hello_world": "Hello, {name} from es!"
}

View file

@ -1,41 +0,0 @@
upstream minio_console {
server ${MINIO_HOST}:${MINIO_CONSOLE_PORT};
}
server {
listen ${PORT};
# Allow special characters in headers
ignore_invalid_headers off;
# Allow any size file to be uploaded.
# Set to a value such as 1000m; to restrict file size to a specific value
client_max_body_size 0;
# Disable buffering
proxy_buffering off;
proxy_request_buffering off;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-NginX-Proxy true;
# This is necessary to pass the correct IP to be hashed
real_ip_header X-Real-IP;
proxy_connect_timeout 300;
# To support websockets in MinIO versions released after January 2023
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Some environments may encounter CORS errors (Kubernetes + Nginx Ingress)
# Uncomment the following line to set the Origin request to an empty string
# proxy_set_header Origin '';
chunked_transfer_encoding off;
proxy_pass http://minio_console; # This uses the upstream directive definition to load balance
}
}

View file

@ -1,90 +1,120 @@
{ {
"name": "taro-stack", "name": "adelie-stack",
"version": "0.0.1", "version": "0.0.1",
"private": true, "private": true,
"scripts": { "scripts": {
"db:push": "drizzle-kit push", "db:push": "drizzle-kit push",
"db:generate": "drizzle-kit generate", "db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate", "db:migrate": "tsx src/lib/server/api/databases/postgres/migrate.ts",
"db:seed": "tsx src/lib/server/api/databases/postgres/seed.ts",
"db:studio": "drizzle-kit studio --verbose", "db:studio": "drizzle-kit studio --verbose",
"dev": "vite dev", "dev": "NODE_OPTIONS=\"--inspect\" vite dev --host",
"build": "vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview",
"test": "npm run test:integration && npm run test:unit", "test:unit": "vitest",
"test": "pnpm test:unit -- --run && pnpm test:e2e",
"test:e2e": "playwright test",
"test:ui": "svelte-kit sync && playwright test --ui",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"initialize": "pnpm install && docker-compose up --no-recreate -d && pnpm db:migrate", "initialize": "pnpm install && docker compose up --no-recreate -d && pnpm db:migrate && pnpm db:seed",
"lint": "prettier --check . && eslint .", "lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --write .", "format": "prettier --plugin-search-dir . --write .",
"test:integration": "playwright test", "storybook": "storybook dev -p 6006",
"test:unit": "vitest" "site:update": "pnpm update -i -L"
}, },
"devDependencies": { "devDependencies": {
"@aws-sdk/client-s3": "^3.651.0", "@biomejs/biome": "^1.9.4",
"@hono/zod-validator": "^0.2.2", "@chromatic-com/storybook": "^3.2.3",
"@lucia-auth/adapter-drizzle": "^1.1.0", "@dicebear/collection": "^9.2.2",
"@paralleldrive/cuid2": "^2.2.2", "@dicebear/converter": "^9.2.2",
"@playwright/test": "^1.47.0", "@dicebear/core": "^9.2.2",
"@sveltejs/adapter-node": "^5.2.2", "@faker-js/faker": "^9.3.0",
"@sveltejs/kit": "^2.5.26", "@playwright/test": "^1.45.3",
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.7", "@storybook/addon-essentials": "^8.4.7",
"@tailwindcss/typography": "^0.5.15", "@storybook/addon-interactions": "^8.4.7",
"@types/eslint": "^9.6.1", "@storybook/addon-svelte-csf": "^5.0.0-next.21",
"@types/node": "^22.5.4", "@storybook/blocks": "^8.4.7",
"@typescript-eslint/eslint-plugin": "^8.5.0", "@storybook/svelte": "^8.4.7",
"@typescript-eslint/parser": "^8.5.0", "@storybook/sveltekit": "^8.4.7",
"@storybook/test": "^8.4.7",
"@sveltejs/adapter-node": "^5.2.9",
"@sveltejs/enhanced-img": "^0.4.4",
"@sveltejs/kit": "^2.15.1",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@types/cookie": "^1.0.0",
"@types/node": "^22.10.2",
"@types/pg": "^8.11.10",
"@types/pg-pool": "^2.0.6",
"@types/qrcode": "^1.5.5",
"arctic": "^1.9.2", "arctic": "^1.9.2",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"bits-ui": "1.0.0-next.76",
"bullmq": "^5.13.0", "bullmq": "^5.13.0",
"chalk": "^5.3.0", "clsx": "^2.1.1",
"dotenv-cli": "^7.4.2", "drizzle-kit": "^0.30.1",
"drizzle-kit": "^0.26.2", "formsnap": "^2.0.0",
"drizzle-orm": "^0.35.1", "lucide-svelte": "^0.469.0",
"eslint": "^9.10.0", "mode-watcher": "^0.5.0",
"eslint-config-prettier": "^9.1.0", "storybook": "^8.4.7",
"eslint-plugin-svelte": "^2.43.0", "svelte": "^5.16.0",
"hono": "^4.6.1", "svelte-check": "^4.0.0",
"ioredis": "^5.4.1", "svelte-meta-tags": "^4.0.4",
"lucia": "^3.2.0", "svelte-preprocess": "^6.0.3",
"lucide-svelte": "^0.441.0", "svelte-sequential-preprocessor": "^2.0.2",
"oslo": "^1.2.1", "svelte-sonner": "^0.3.28",
"pg": "^8.12.0", "sveltekit-flash-message": "^2.4.4",
"postcss": "^8.4.45", "sveltekit-superforms": "^2.22.1",
"postgres": "^3.4.4", "tailwind-merge": "^2.6.0",
"prettier": "^3.3.3", "tailwind-variants": "^0.3.0",
"prettier-plugin-svelte": "^3.2.6", "tailwindcss": "^3.4.9",
"prettier-plugin-tailwindcss": "^0.6.6", "tailwindcss-animate": "^1.0.7",
"reflect-metadata": "^0.2.2", "tsx": "^4.19.2",
"svelte": "5.0.0-next.164", "typescript": "^5.0.0",
"svelte-check": "^4.0.2", "vite": "^6.0.6",
"svelte-dnd-action": "^0.9.50", "vitest": "^2.0.4",
"svelte-eslint-parser": "^0.41.0", "zod": "^3.24.1"
"sveltekit-search-params": "^3.0.0",
"sveltekit-superforms": "^2.17.0",
"tailwindcss": "^3.4.11",
"tsyringe": "^4.8.0",
"typescript": "^5.6.2",
"vite": "^5.4.4",
"vitest": "^2.1.0",
"zod": "^3.23.8"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@hono/swagger-ui": "^0.5.0",
"@hono/zod-openapi": "^0.18.3",
"@hono/zod-validator": "^0.4.2",
"@inlang/paraglide-sveltekit": "^0.15.0",
"@internationalized/date": "^3.5.5", "@internationalized/date": "^3.5.5",
"bits-ui": "^0.21.13", "@needle-di/core": "^0.8.4",
"clsx": "^2.1.1", "@oslojs/binary": "^1.0.0",
"cmdk-sv": "^0.0.18", "@oslojs/crypto": "^1.0.1",
"embla-carousel-svelte": "^8.2.1", "@oslojs/encoding": "^1.1.0",
"formsnap": "^1.0.1", "@oslojs/jwt": "^0.3.0",
"hono-rate-limiter": "^0.4.0", "@oslojs/oauth2": "^0.5.0",
"mode-watcher": "^0.4.1", "@oslojs/otp": "^1.0.0",
"paneforge": "^0.0.5", "@oslojs/webauthn": "^1.0.0",
"@scalar/hono-api-reference": "^0.5.162",
"@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.9",
"@tailwindcss/typography": "^0.5.15",
"arctic": "^2.3.3",
"argon2": "^0.41.1",
"dayjs": "^1.11.13",
"dotenv": "^16.4.7",
"drizzle-orm": "^0.38.3",
"drizzle-zod": "^0.6.1",
"hono": "^4.6.15",
"hono-pino": "^0.7.0",
"hono-rate-limiter": "^0.4.2",
"hono-zod-openapi": "^0.5.0",
"ioredis": "^5.4.2",
"minio": "^8.0.3",
"nanoid": "^5.0.9",
"pg": "^8.13.1",
"pg-pool": "^3.7.0",
"pino": "^9.6.0",
"pino-pretty": "^13.0.0",
"postgres": "^3.4.4",
"rate-limit-redis": "^4.2.0", "rate-limit-redis": "^4.2.0",
"redis": "^4.7.0", "sharp": "^0.33.5",
"redis-om": "^0.4.6", "sonner": "^1.7.1",
"svelte-sonner": "^0.3.28", "stoker": "^1.4.2"
"tailwind-merge": "^2.5.2",
"tailwind-variants": "^0.2.1",
"vaul-svelte": "^0.3.2"
} }
} }

View file

@ -1,12 +1,10 @@
import type { PlaywrightTestConfig } from '@playwright/test'; import { defineConfig } from '@playwright/test';
const config: PlaywrightTestConfig = { export default defineConfig({
webServer: { webServer: {
command: 'npm run build && npm run preview', command: 'npm run build && npm run preview',
port: 4173 port: 4173
}, },
testDir: 'tests',
testMatch: /(.+\.)?(test|spec)\.[jt]s/
};
export default config; testDir: 'e2e'
});

File diff suppressed because it is too large Load diff

1
project.inlang/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
cache

View file

@ -0,0 +1 @@
eb7d81211e6faa5e843476a33150228f5db02e3c62748d6eff4e45b709691d18

View file

@ -0,0 +1,20 @@
{
"$schema": "https://inlang.com/schema/project-settings",
"modules": [
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-empty-pattern@1/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-identical-pattern@1/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-missing-translation@1/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-without-source@1/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-valid-js-identifier@1/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@2/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@0/dist/index.js"
],
"plugin.inlang.messageFormat": {
"pathPattern": "./messages/{languageTag}.json"
},
"sourceLanguageTag": "en",
"languageTags": [
"en",
"es"
]
}

View file

@ -1,101 +0,0 @@
services:
# Web
- type: web
name: web
runtime: node
region: oregon # optional (defaults to oregon)
plan: starter # optional (defaults to starter instance type)
branch: main # optional (defaults to master)
buildCommand: npm install --force && npm run build
startCommand: npm run db:migrate && node build/index.js
healthCheckPath: /
envVars:
- key: STORAGE_API_SECRET_KEY
fromService:
name: minio-server
type: web
property: MINIO_ROOT_PASSWORD
- key: STORAGE_ACCESS_KEY
fromService:
name: minio-server
type: web
property: MINIO_ROOT_USER
- key: STORAGE_API_URL
fromService:
name: minio-server
type: web
property: connectionString
- key: DATABASE_URL
fromDatabase:
name: tofustack
property: connectionString
- key: REDIS_URL
fromService:
name: redis
type: redis
property: connectionString
- key: PUBLIC_ORIGIN
fromService:
name: web
type: web
property: host
# Redis
- type: redis
name: redis
ipAllowList: [] # Only allow internal connections
# MinIO Server
- type: web
name: minio-server
healthCheckPath: /minio/health/liveweb
runtime: image
image:
url: docker.io/minio/minio:latest
dockerCommand: minio server /data --address $HOST:$PORT --console-address $HOST:$CONSOLE_PORT
# Use the following 'dockerCommand' if removing the 'minio-console'
# web service
# dockerCommand: minio server /data --address $HOST:$PORT
autoDeploy: false
disk:
name: data
mountPath: /data
envVars:
- key: MINIO_ROOT_USER
generateValue: true
- key: MINIO_ROOT_PASSWORD
generateValue: true
- key: HOST
value: "0.0.0.0"
- key: PORT
value: 9000
- key: CONSOLE_PORT
value: 9090
# Uncomment the following key/value pair if you are removing the
# 'minio-console' web service
# - key: MINIO_BROWSER
# value: "off"
# MinIO Console
- type: web
name: minio-console
runtime: docker
dockerContext: /
dockerfilePath: ./Dockerfile.minio
autoDeploy: false
envVars:
- key: PORT
value: 10000
- key: MINIO_HOST
fromService:
name: minio-server
type: web
property: host
- key: MINIO_CONSOLE_PORT
fromService:
name: minio-server
type: web
envVarKey: CONSOLE_PORT
databases:
- name: db
databaseName: tofustack
ipAllowList: []

View file

@ -6,65 +6,62 @@
:root { :root {
--background: 0 0% 100%; --background: 0 0% 100%;
--foreground: 222.2 84% 4.9%; --foreground: 222.2 84% 4.9%;
--muted: 210 40% 96.1%; --muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%; --muted-foreground: 215.4 16.3% 46.9%;
--popover: 0 0% 100%; --popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%; --popover-foreground: 222.2 84% 4.9%;
--card: 0 0% 100%; --card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%; --card-foreground: 222.2 84% 4.9%;
--border: 214.3 31.8% 91.4%; --border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%; --input: 214.3 31.8% 91.4%;
--primary: 222.2 47.4% 11.2%; --primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%; --primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%; --secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%; --secondary-foreground: 222.2 47.4% 11.2%;
--accent: 210 40% 96.1%; --accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%; --accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 72.2% 50.6%; --destructive: 0 72.2% 50.6%;
--destructive-foreground: 210 40% 98%; --destructive-foreground: 210 40% 98%;
--ring: 222.2 84% 4.9%; --ring: 222.2 84% 4.9%;
--radius: 0.5rem; --radius: 0.5rem;
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
} }
.dark { .dark {
--background: 222.2 84% 4.9%; --background: 222.2 84% 4.9%;
--foreground: 210 40% 98%; --foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%; --muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%; --muted-foreground: 215 20.2% 65.1%;
--popover: 222.2 84% 4.9%; --popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%; --popover-foreground: 210 40% 98%;
--card: 222.2 84% 4.9%; --card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%; --card-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%; --border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%; --input: 217.2 32.6% 17.5%;
--primary: 210 40% 98%; --primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%; --primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%; --secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%; --secondary-foreground: 210 40% 98%;
--accent: 217.2 32.6% 17.5%; --accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%; --accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%; --destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%; --destructive-foreground: 210 40% 98%;
--ring: 212.7 26.8% 83.9%;
--ring: hsl(212.7,26.8%,83.9); --sidebar-background: 240 5.9% 10%;
--sidebar-foreground: 240 4.8% 95.9%;
--sidebar-primary: 224.3 76.3% 48%;
--sidebar-primary-foreground: 0 0% 100%;
--sidebar-accent: 240 3.7% 15.9%;
--sidebar-accent-foreground: 240 4.8% 95.9%;
--sidebar-border: 240 3.7% 15.9%;
--sidebar-ring: 217.2 91.2% 59.8%;
} }
} }

29
src/app.d.ts vendored
View file

@ -7,24 +7,41 @@ import type { Security } from '$lib/utils/security';
// for information about these interfaces // for information about these interfaces
declare global { declare global {
namespace App { namespace App {
// interface Error {} interface PageData {
flash?: {
type: 'success' | 'error' | 'info';
message: string;
data?: Record<string, unknown>;
};
}
interface Locals { interface Locals {
api: ApiClient['api']; api: ApiClient['api'];
parseApiResponse: typeof parseApiResponse; parseApiResponse: typeof parseApiResponse;
getAuthedUser: () => Promise<Returned<User> | null>; getAuthedUser: () => Promise<Returned<User> | null>;
getAuthedUserOrThrow: (redirectTo: string) => Promise<Returned<User>>; getAuthedUserOrThrow: (redirectTo: string) => Promise<Returned<User>>;
} }
// interface PageData {}
// interface PageState {} // interface PageState {}
// interface Platform {} // interface Platform {}
namespace Superforms { namespace Superforms {
type Message = { type Message = {
type: 'error' | 'success', type: 'error' | 'success' | 'info';
text: string text: string;
} }
} }
interface Error {
code?: string;
errorId?: string;
}
}
interface Document {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
startViewTransition: (callback: never) => void; // Add your custom property/method here
} }
} }
export { }; // THIS IS IMPORTANT!!!
// biome-ignore lint/complexity/noUselessEmptyExport: <explanation>
// biome-ignore lint/style/useExportType: <explanation>
export {};

View file

@ -1,5 +1,5 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="%paraglide.lang%" dir="%paraglide.textDirection%">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" /> <link rel="icon" href="%sveltekit.assets%/favicon.png" />

View file

@ -1,30 +1,35 @@
import 'reflect-metadata' import { redirect, type Handle, type ServerInit } from '@sveltejs/kit';
import { hc } from 'hono/client';
import { redirect, type Handle } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks'; import { sequence } from '@sveltejs/kit/hooks';
import type { ApiRoutes } from '$lib/server/api'; import { startServer } from '$lib/server/api';
import { parseApiResponse } from '$lib/utils/api'; import { honoClient, parseApiResponse } from '$lib/utils/api';
import { StatusCodes } from '$lib/constants/status-codes'; import { StatusCodes } from '$lib/constants/status-codes';
import { i18n } from './lib/i18n';
const handleParaglide: Handle = i18n.handle();
export const app = await startServer();
const apiClient: Handle = async ({ event, resolve }) => { const apiClient: Handle = async ({ event, resolve }) => {
/* ------------------------------ Register api ------------------------------ */ /* ------------------------------ Register api ------------------------------ */
const { api } = hc<ApiRoutes>('/', { const { api } = honoClient({
fetch: event.fetch, fetch: event.fetch,
headers: { headers: {
'x-forwarded-for': event.getClientAddress(), 'x-forwarded-for': event.url.host.includes('sveltekit-prerender') ? '127.0.0.1' : event.getClientAddress(),
host: event.request.headers.get('host') || '' host: event.request.headers.get('host') || '',
} },
}); });
/* ----------------------------- Auth functions ----------------------------- */ /* ----------------------------- Auth functions ----------------------------- */
async function getAuthedUser() { async function getAuthedUser() {
const { data } = await api.iam.me.$get().then(parseApiResponse) const { data } = await api.users.me.$get().then(parseApiResponse);
return data && data.user; return { user: data?.user, session: data?.session };
} }
async function getAuthedUserOrThrow(redirectTo = '/') { async function getAuthedUserOrThrow() {
const { data } = await api.iam.me.$get().then(parseApiResponse); const { data } = await api.users.me.$get().then(parseApiResponse);
if (!data || !data.user) throw redirect(StatusCodes.TEMPORARY_REDIRECT, redirectTo); if (!data || !data.user) {
throw redirect(StatusCodes.TEMPORARY_REDIRECT, '/');
}
return data?.user; return data?.user;
} }
@ -39,4 +44,4 @@ const apiClient: Handle = async ({ event, resolve }) => {
return response; return response;
}; };
export const handle = sequence(apiClient); export const handle: Handle = sequence(apiClient, handleParaglide);

2
src/hooks.ts Normal file
View file

@ -0,0 +1,2 @@
import { i18n } from '$lib/i18n';
export const reroute = i18n.reroute();

View file

@ -1,15 +0,0 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/ui';
import type { Snippet } from 'svelte';
interface Props extends HTMLAttributes<HTMLDivElement> {
children: Snippet;
}
let { class: classNames, children, ...restProps }: Props = $props();
</script>
<div {...restProps} class={cn('mx-auto w-full max-w-6xl px-0 md:px-6', classNames)}>
{@render children()}
</div>

View file

@ -1,32 +0,0 @@
<script lang="ts">
import { cn } from '$lib/utils/ui';
import { PinInput, type PinInputProps } from 'bits-ui';
interface Props extends Omit<PinInputProps, 'value'> {
value: string;
inputCount?: number;
}
let { value = $bindable(), inputCount = 6, ...rest }: Props = $props();
let pin = $state<string[] | undefined>(value?.split('') ?? []);
let inputs = $derived(Array(inputCount).fill(null));
$effect(() => {
value = pin?.join('') ?? '';
});
</script>
<PinInput.Root
{...rest}
bind:value={pin}
class={cn('flex items-center gap-2', rest.class)}
type="text"
placeholder=""
>
{#each inputs as _}
<PinInput.Input
class="flex h-14 w-10 rounded-md border border-input bg-background px-3 py-2 text-center text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
/>
{/each}
<PinInput.HiddenInput />
</PinInput.Root>

View file

@ -0,0 +1,25 @@
<script lang="ts">
import Moon from 'lucide-svelte/icons/moon';
import Sun from 'lucide-svelte/icons/sun';
import { buttonVariants } from '$lib/components/ui/button/index.js';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu/index.js';
import { resetMode, setMode } from 'mode-watcher';
</script>
<DropdownMenu.Root>
<DropdownMenu.Trigger class={buttonVariants({ variant: 'outline', size: 'icon' })}>
<Sun
class="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
/>
<Moon
class="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
/>
<span class="sr-only">Toggle theme</span>
</DropdownMenu.Trigger>
<DropdownMenu.Content align="end">
<DropdownMenu.Item onclick={() => setMode('light')}>Light</DropdownMenu.Item>
<DropdownMenu.Item onclick={() => setMode('dark')}>Dark</DropdownMenu.Item>
<DropdownMenu.Item onclick={() => resetMode()}>System</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Root>

View file

@ -1,25 +0,0 @@
<script lang="ts">
import { Accordion as AccordionPrimitive } from "bits-ui";
import { slide } from "svelte/transition";
import { cn } from "$lib/utils/ui.js";
type $$Props = AccordionPrimitive.ContentProps;
let className: $$Props["class"] = undefined;
export let transition: $$Props["transition"] = slide;
export let transitionConfig: $$Props["transitionConfig"] = {
duration: 200,
};
export { className as class };
</script>
<AccordionPrimitive.Content
class={cn("overflow-hidden text-sm transition-all", className)}
{transition}
{transitionConfig}
{...$$restProps}
>
<div class="pb-4 pt-0">
<slot />
</div>
</AccordionPrimitive.Content>

View file

@ -1,14 +0,0 @@
<script lang="ts">
import { Accordion as AccordionPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = AccordionPrimitive.ItemProps;
let className: $$Props["class"] = undefined;
export let value: $$Props["value"];
export { className as class };
</script>
<AccordionPrimitive.Item {value} class={cn("border-b", className)} {...$$restProps}>
<slot />
</AccordionPrimitive.Item>

View file

@ -1,26 +0,0 @@
<script lang="ts">
import { Accordion as AccordionPrimitive } from "bits-ui";
import ChevronDown from "lucide-svelte/icons/chevron-down";
import { cn } from "$lib/utils/ui.js";
type $$Props = AccordionPrimitive.TriggerProps;
type $$Events = AccordionPrimitive.TriggerEvents;
let className: $$Props["class"] = undefined;
export let level: AccordionPrimitive.HeaderProps["level"] = 3;
export { className as class };
</script>
<AccordionPrimitive.Header {level} class="flex">
<AccordionPrimitive.Trigger
class={cn(
"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
className
)}
{...$$restProps}
on:click
>
<slot />
<ChevronDown class="h-4 w-4 transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>

View file

@ -1,17 +0,0 @@
import { Accordion as AccordionPrimitive } from "bits-ui";
import Content from "./accordion-content.svelte";
import Item from "./accordion-item.svelte";
import Trigger from "./accordion-trigger.svelte";
const Root = AccordionPrimitive.Root;
export {
Root,
Content,
Item,
Trigger,
//
Root as Accordion,
Content as AccordionContent,
Item as AccordionItem,
Trigger as AccordionTrigger,
};

View file

@ -1,21 +0,0 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { buttonVariants } from "$lib/components/ui/button/index.js";
import { cn } from "$lib/utils/ui.js";
type $$Props = AlertDialogPrimitive.ActionProps;
type $$Events = AlertDialogPrimitive.ActionEvents;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<AlertDialogPrimitive.Action
class={cn(buttonVariants(), className)}
{...$$restProps}
on:click
on:keydown
let:builder
>
<slot {builder} />
</AlertDialogPrimitive.Action>

View file

@ -1,21 +0,0 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { buttonVariants } from "$lib/components/ui/button/index.js";
import { cn } from "$lib/utils/ui.js";
type $$Props = AlertDialogPrimitive.CancelProps;
type $$Events = AlertDialogPrimitive.CancelEvents;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<AlertDialogPrimitive.Cancel
class={cn(buttonVariants({ variant: "outline" }), "mt-2 sm:mt-0", className)}
{...$$restProps}
on:click
on:keydown
let:builder
>
<slot {builder} />
</AlertDialogPrimitive.Cancel>

View file

@ -1,28 +0,0 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import * as AlertDialog from "./index.js";
import { cn, flyAndScale } from "$lib/utils/ui.js";
type $$Props = AlertDialogPrimitive.ContentProps;
export let transition: $$Props["transition"] = flyAndScale;
export let transitionConfig: $$Props["transitionConfig"] = undefined;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<AlertDialog.Portal>
<AlertDialog.Overlay />
<AlertDialogPrimitive.Content
{transition}
{transitionConfig}
class={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg sm:rounded-lg md:w-full",
className
)}
{...$$restProps}
>
<slot />
</AlertDialogPrimitive.Content>
</AlertDialog.Portal>

View file

@ -1,16 +0,0 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = AlertDialogPrimitive.DescriptionProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<AlertDialogPrimitive.Description
class={cn("text-sm text-muted-foreground", className)}
{...$$restProps}
>
<slot />
</AlertDialogPrimitive.Description>

View file

@ -1,16 +0,0 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<div
class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
{...$$restProps}
>
<slot />
</div>

View file

@ -1,13 +0,0 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<div class={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...$$restProps}>
<slot />
</div>

View file

@ -1,21 +0,0 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { fade } from "svelte/transition";
import { cn } from "$lib/utils/ui.js";
type $$Props = AlertDialogPrimitive.OverlayProps;
let className: $$Props["class"] = undefined;
export let transition: $$Props["transition"] = fade;
export let transitionConfig: $$Props["transitionConfig"] = {
duration: 150,
};
export { className as class };
</script>
<AlertDialogPrimitive.Overlay
{transition}
{transitionConfig}
class={cn("fixed inset-0 z-50 bg-background/80 backdrop-blur-sm ", className)}
{...$$restProps}
/>

View file

@ -1,9 +0,0 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
type $$Props = AlertDialogPrimitive.PortalProps;
</script>
<AlertDialogPrimitive.Portal {...$$restProps}>
<slot />
</AlertDialogPrimitive.Portal>

View file

@ -1,14 +0,0 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = AlertDialogPrimitive.TitleProps;
let className: $$Props["class"] = undefined;
export let level: $$Props["level"] = "h3";
export { className as class };
</script>
<AlertDialogPrimitive.Title class={cn("text-lg font-semibold", className)} {level} {...$$restProps}>
<slot />
</AlertDialogPrimitive.Title>

View file

@ -1,40 +0,0 @@
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import Title from "./alert-dialog-title.svelte";
import Action from "./alert-dialog-action.svelte";
import Cancel from "./alert-dialog-cancel.svelte";
import Portal from "./alert-dialog-portal.svelte";
import Footer from "./alert-dialog-footer.svelte";
import Header from "./alert-dialog-header.svelte";
import Overlay from "./alert-dialog-overlay.svelte";
import Content from "./alert-dialog-content.svelte";
import Description from "./alert-dialog-description.svelte";
const Root = AlertDialogPrimitive.Root;
const Trigger = AlertDialogPrimitive.Trigger;
export {
Root,
Title,
Action,
Cancel,
Portal,
Footer,
Header,
Trigger,
Overlay,
Content,
Description,
//
Root as AlertDialog,
Title as AlertDialogTitle,
Action as AlertDialogAction,
Cancel as AlertDialogCancel,
Portal as AlertDialogPortal,
Footer as AlertDialogFooter,
Header as AlertDialogHeader,
Trigger as AlertDialogTrigger,
Overlay as AlertDialogOverlay,
Content as AlertDialogContent,
Description as AlertDialogDescription,
};

View file

@ -1,13 +1,16 @@
<script lang="ts"> <script lang="ts">
import type { WithElementRef } from "bits-ui";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js"; import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLDivElement>; let {
ref = $bindable(null),
let className: $$Props["class"] = undefined; class: className,
export { className as class }; children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div class={cn("text-sm [&_p]:leading-relaxed", className)} {...$$restProps}> <div bind:this={ref} class={cn("text-sm [&_p]:leading-relaxed", className)} {...restProps}>
<slot /> {@render children?.()}
</div> </div>

View file

@ -1,21 +1,25 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import type { HeadingLevel } from "./index.js"; import type { WithElementRef } from "bits-ui";
import { cn } from "$lib/utils/ui.js"; import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLHeadingElement> & { let {
level?: HeadingLevel; ref = $bindable(null),
}; class: className,
level = 5,
let className: $$Props["class"] = undefined; children,
export let level: $$Props["level"] = "h5"; ...restProps
export { className as class }; }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
level?: 1 | 2 | 3 | 4 | 5 | 6;
} = $props();
</script> </script>
<svelte:element <div
this={level} role="heading"
aria-level={level}
bind:this={ref}
class={cn("mb-1 font-medium leading-none tracking-tight", className)} class={cn("mb-1 font-medium leading-none tracking-tight", className)}
{...$$restProps} {...restProps}
> >
<slot /> {@render children?.()}
</svelte:element> </div>

View file

@ -1,17 +1,39 @@
<script lang="ts"> <script lang="ts" module>
import type { HTMLAttributes } from "svelte/elements"; import { type VariantProps, tv } from "tailwind-variants";
import { type Variant, alertVariants } from "./index.js";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLAttributes<HTMLDivElement> & { export const alertVariants = tv({
variant?: Variant; base: "[&>svg]:text-foreground relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg~*]:pl-7",
}; variants: {
variant: {
default: "bg-background text-foreground",
destructive:
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
},
},
defaultVariants: {
variant: "default",
},
});
let className: $$Props["class"] = undefined; export type AlertVariant = VariantProps<typeof alertVariants>["variant"];
export let variant: $$Props["variant"] = "default";
export { className as class };
</script> </script>
<div class={cn(alertVariants({ variant }), className)} {...$$restProps} role="alert"> <script lang="ts">
<slot /> import type { HTMLAttributes } from "svelte/elements";
import type { WithElementRef } from "bits-ui";
import { cn } from "$lib/utils.js";
let {
ref = $bindable(null),
class: className,
variant = "default",
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
variant?: AlertVariant;
} = $props();
</script>
<div bind:this={ref} class={cn(alertVariants({ variant }), className)} {...restProps} role="alert">
{@render children?.()}
</div> </div>

View file

@ -1,26 +1,7 @@
import { type VariantProps, tv } from "tailwind-variants";
import Root from "./alert.svelte"; import Root from "./alert.svelte";
import Description from "./alert-description.svelte"; import Description from "./alert-description.svelte";
import Title from "./alert-title.svelte"; import Title from "./alert-title.svelte";
export { alertVariants, type AlertVariant } from "./alert.svelte";
export const alertVariants = tv({
base: "relative w-full rounded-lg border p-4 [&:has(svg)]:pl-11 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
variants: {
variant: {
default: "bg-background text-foreground",
destructive:
"border-destructive/50 text-destructive text-destructive dark:border-destructive [&>svg]:text-destructive",
},
},
defaultVariants: {
variant: "default",
},
});
export type Variant = VariantProps<typeof alertVariants>["variant"];
export type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
export { export {
Root, Root,

View file

@ -1,11 +0,0 @@
<script lang="ts">
import { AspectRatio as AspectRatioPrimitive } from "bits-ui";
type $$Props = AspectRatioPrimitive.Props;
export let ratio: $$Props["ratio"] = 4 / 3;
</script>
<AspectRatioPrimitive.Root {ratio} {...$$restProps}>
<slot />
</AspectRatioPrimitive.Root>

View file

@ -1,3 +0,0 @@
import Root from "./aspect-ratio.svelte";
export { Root, Root as AspectRatio };

View file

@ -1,16 +0,0 @@
<script lang="ts">
import { Avatar as AvatarPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = AvatarPrimitive.FallbackProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<AvatarPrimitive.Fallback
class={cn("flex h-full w-full items-center justify-center rounded-full bg-muted", className)}
{...$$restProps}
>
<slot />
</AvatarPrimitive.Fallback>

View file

@ -1,18 +0,0 @@
<script lang="ts">
import { Avatar as AvatarPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = AvatarPrimitive.ImageProps;
let className: $$Props["class"] = undefined;
export let src: $$Props["src"] = undefined;
export let alt: $$Props["alt"] = undefined;
export { className as class };
</script>
<AvatarPrimitive.Image
{src}
{alt}
class={cn("aspect-square h-full w-full", className)}
{...$$restProps}
/>

View file

@ -1,18 +0,0 @@
<script lang="ts">
import { Avatar as AvatarPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = AvatarPrimitive.Props;
let className: $$Props["class"] = undefined;
export let delayMs: $$Props["delayMs"] = undefined;
export { className as class };
</script>
<AvatarPrimitive.Root
{delayMs}
class={cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className)}
{...$$restProps}
>
<slot />
</AvatarPrimitive.Root>

View file

@ -1,13 +0,0 @@
import Root from "./avatar.svelte";
import Image from "./avatar-image.svelte";
import Fallback from "./avatar-fallback.svelte";
export {
Root,
Image,
Fallback,
//
Root as Avatar,
Image as AvatarImage,
Fallback as AvatarFallback,
};

View file

@ -1,18 +0,0 @@
<script lang="ts">
import { type Variant, badgeVariants } from "./index.js";
import { cn } from "$lib/utils/ui.js";
let className: string | undefined | null = undefined;
export let href: string | undefined = undefined;
export let variant: Variant = "default";
export { className as class };
</script>
<svelte:element
this={href ? "a" : "span"}
{href}
class={cn(badgeVariants({ variant, className }))}
{...$$restProps}
>
<slot />
</svelte:element>

View file

@ -1,21 +0,0 @@
import { type VariantProps, tv } from "tailwind-variants";
export { default as Badge } from "./badge.svelte";
export const badgeVariants = tv({
base: "inline-flex select-none items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
variants: {
variant: {
default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
secondary:
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive:
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
outline: "text-foreground",
},
},
defaultVariants: {
variant: "default",
},
});
export type Variant = VariantProps<typeof badgeVariants>["variant"];

View file

@ -1,24 +0,0 @@
<script lang="ts">
import Ellipsis from "lucide-svelte/icons/ellipsis";
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLAttributes<HTMLSpanElement> & {
el?: HTMLSpanElement;
};
export let el: $$Props["el"] = undefined;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<span
bind:this={el}
role="presentation"
aria-hidden="true"
class={cn("flex h-9 w-9 items-center justify-center", className)}
{...$$restProps}
>
<Ellipsis class="h-4 w-4" />
<span class="sr-only">More</span>
</span>

View file

@ -1,16 +0,0 @@
<script lang="ts">
import type { HTMLLiAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLLiAttributes & {
el?: HTMLLIElement;
};
export let el: $$Props["el"] = undefined;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<li bind:this={el} class={cn("inline-flex items-center gap-1.5", className)}>
<slot />
</li>

View file

@ -1,31 +0,0 @@
<script lang="ts">
import type { HTMLAnchorAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLAnchorAttributes & {
el?: HTMLAnchorElement;
asChild?: boolean;
};
export let href: $$Props["href"] = undefined;
export let el: $$Props["el"] = undefined;
export let asChild: $$Props["asChild"] = false;
let className: $$Props["class"] = undefined;
export { className as class };
let attrs: Record<string, unknown>;
$: attrs = {
class: cn("transition-colors hover:text-foreground", className),
href,
...$$restProps,
};
</script>
{#if asChild}
<slot {attrs} />
{:else}
<a bind:this={el} {...attrs} {href}>
<slot {attrs} />
</a>
{/if}

View file

@ -1,23 +0,0 @@
<script lang="ts">
import type { HTMLOlAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLOlAttributes & {
el?: HTMLOListElement;
};
export let el: $$Props["el"] = undefined;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<ol
bind:this={el}
class={cn(
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
className
)}
{...$$restProps}
>
<slot />
</ol>

View file

@ -1,23 +0,0 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLAttributes<HTMLSpanElement> & {
el?: HTMLSpanElement;
};
export let el: $$Props["el"] = undefined;
export let className: $$Props["class"] = undefined;
export { className as class };
</script>
<span
bind:this={el}
role="link"
aria-disabled="true"
aria-current="page"
class={cn("font-normal text-foreground", className)}
{...$$restProps}
>
<slot />
</span>

View file

@ -1,25 +0,0 @@
<script lang="ts">
import type { HTMLLiAttributes } from "svelte/elements";
import ChevronRight from "lucide-svelte/icons/chevron-right";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLLiAttributes & {
el?: HTMLLIElement;
};
export let el: $$Props["el"] = undefined;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<li
role="presentation"
aria-hidden="true"
class={cn("[&>svg]:size-3.5", className)}
bind:this={el}
{...$$restProps}
>
<slot>
<ChevronRight />
</slot>
</li>

View file

@ -1,15 +0,0 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
type $$Props = HTMLAttributes<HTMLElement> & {
el?: HTMLElement;
};
export let el: $$Props["el"] = undefined;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<nav class={className} bind:this={el} aria-label="breadcrumb" {...$$restProps}>
<slot />
</nav>

View file

@ -1,25 +0,0 @@
import Root from "./breadcrumb.svelte";
import Ellipsis from "./breadcrumb-ellipsis.svelte";
import Item from "./breadcrumb-item.svelte";
import Separator from "./breadcrumb-separator.svelte";
import Link from "./breadcrumb-link.svelte";
import List from "./breadcrumb-list.svelte";
import Page from "./breadcrumb-page.svelte";
export {
Root,
Ellipsis,
Item,
Separator,
Link,
List,
Page,
//
Root as Breadcrumb,
Ellipsis as BreadcrumbEllipsis,
Item as BreadcrumbItem,
Separator as BreadcrumbSeparator,
Link as BreadcrumbLink,
List as BreadcrumbList,
Page as BreadcrumbPage,
};

View file

@ -1,25 +1,74 @@
<script lang="ts"> <script lang="ts" module>
import { Button as ButtonPrimitive } from "bits-ui"; import type { WithElementRef } from "bits-ui";
import { type Events, type Props, buttonVariants } from "./index.js"; import type { HTMLAnchorAttributes, HTMLButtonAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js"; import { type VariantProps, tv } from "tailwind-variants";
type $$Props = Props; export const buttonVariants = tv({
type $$Events = Events; base: "ring-offset-background focus-visible:ring-ring inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border-input bg-background hover:bg-accent hover:text-accent-foreground border",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
});
let className: $$Props["class"] = undefined; export type ButtonVariant = VariantProps<typeof buttonVariants>["variant"];
export let variant: $$Props["variant"] = "default"; export type ButtonSize = VariantProps<typeof buttonVariants>["size"];
export let size: $$Props["size"] = "default";
export let builders: $$Props["builders"] = []; export type ButtonProps = WithElementRef<HTMLButtonAttributes> &
export { className as class }; WithElementRef<HTMLAnchorAttributes> & {
variant?: ButtonVariant;
size?: ButtonSize;
};
</script> </script>
<ButtonPrimitive.Root <script lang="ts">
{builders} import { cn } from "$lib/utils.js";
class={cn(buttonVariants({ variant, size, className }))}
type="button" let {
{...$$restProps} class: className,
on:click variant = "default",
on:keydown size = "default",
> ref = $bindable(null),
<slot /> href = undefined,
</ButtonPrimitive.Root> type = "button",
children,
...restProps
}: ButtonProps = $props();
</script>
{#if href}
<a
bind:this={ref}
class={cn(buttonVariants({ variant, size }), className)}
{href}
{...restProps}
>
{@render children?.()}
</a>
{:else}
<button
bind:this={ref}
class={cn(buttonVariants({ variant, size }), className)}
{type}
{...restProps}
>
{@render children?.()}
</button>
{/if}

View file

@ -1,49 +1,17 @@
import { type VariantProps, tv } from "tailwind-variants"; import Root, {
import type { Button as ButtonPrimitive } from "bits-ui"; type ButtonProps,
import Root from "./button.svelte"; type ButtonSize,
type ButtonVariant,
const buttonVariants = tv({ buttonVariants,
base: "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", } from "./button.svelte";
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
});
type Variant = VariantProps<typeof buttonVariants>["variant"];
type Size = VariantProps<typeof buttonVariants>["size"];
type Props = ButtonPrimitive.Props & {
variant?: Variant;
size?: Size;
};
type Events = ButtonPrimitive.Events;
export { export {
Root, Root,
type Props, type ButtonProps as Props,
type Events,
// //
Root as Button, Root as Button,
type Props as ButtonProps,
type Events as ButtonEvents,
buttonVariants, buttonVariants,
type ButtonProps,
type ButtonSize,
type ButtonVariant,
}; };

View file

@ -1,21 +0,0 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = CalendarPrimitive.CellProps;
export let date: $$Props["date"];
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<CalendarPrimitive.Cell
{date}
class={cn(
"relative h-9 w-9 p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([data-selected])]:rounded-md [&:has([data-selected])]:bg-accent [&:has([data-selected][data-outside-month])]:bg-accent/50",
className
)}
{...$$restProps}
>
<slot />
</CalendarPrimitive.Cell>

View file

@ -1,42 +0,0 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from "bits-ui";
import { buttonVariants } from "$lib/components/ui/button/index.js";
import { cn } from "$lib/utils/ui.js";
type $$Props = CalendarPrimitive.DayProps;
type $$Events = CalendarPrimitive.DayEvents;
export let date: $$Props["date"];
export let month: $$Props["month"];
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<CalendarPrimitive.Day
on:click
{date}
{month}
class={cn(
buttonVariants({ variant: "ghost" }),
"h-9 w-9 p-0 font-normal ",
"[&[data-today]:not([data-selected])]:bg-accent [&[data-today]:not([data-selected])]:text-accent-foreground",
// Selected
"data-[selected]:bg-primary data-[selected]:text-primary-foreground data-[selected]:opacity-100 data-[selected]:hover:bg-primary data-[selected]:hover:text-primary-foreground data-[selected]:focus:bg-primary data-[selected]:focus:text-primary-foreground",
// Disabled
"data-[disabled]:text-muted-foreground data-[disabled]:opacity-50",
// Unavailable
"data-[unavailable]:text-destructive-foreground data-[unavailable]:line-through",
// Outside months
"data-[outside-month]:pointer-events-none data-[outside-month]:text-muted-foreground data-[outside-month]:opacity-50 [&[data-outside-month][data-selected]]:bg-accent/50 [&[data-outside-month][data-selected]]:text-muted-foreground [&[data-outside-month][data-selected]]:opacity-30",
className
)}
{...$$restProps}
let:selected
let:disabled
let:unavailable
let:builder
>
<slot {selected} {disabled} {unavailable} {builder}>
{date.day}
</slot>
</CalendarPrimitive.Day>

View file

@ -1,13 +0,0 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = CalendarPrimitive.GridBodyProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<CalendarPrimitive.GridBody class={cn(className)} {...$$restProps}>
<slot />
</CalendarPrimitive.GridBody>

View file

@ -1,13 +0,0 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = CalendarPrimitive.GridHeadProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<CalendarPrimitive.GridHead class={cn(className)} {...$$restProps}>
<slot />
</CalendarPrimitive.GridHead>

View file

@ -1,13 +0,0 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = CalendarPrimitive.GridRowProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<CalendarPrimitive.GridRow class={cn("flex", className)} {...$$restProps}>
<slot />
</CalendarPrimitive.GridRow>

View file

@ -1,13 +0,0 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = CalendarPrimitive.GridProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<CalendarPrimitive.Grid class={cn("w-full border-collapse space-y-1", className)} {...$$restProps}>
<slot />
</CalendarPrimitive.Grid>

View file

@ -1,16 +0,0 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = CalendarPrimitive.HeadCellProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<CalendarPrimitive.HeadCell
class={cn("w-9 rounded-md text-[0.8rem] font-normal text-muted-foreground", className)}
{...$$restProps}
>
<slot />
</CalendarPrimitive.HeadCell>

View file

@ -1,16 +0,0 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = CalendarPrimitive.HeaderProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<CalendarPrimitive.Header
class={cn("relative flex w-full items-center justify-between pt-1", className)}
{...$$restProps}
>
<slot />
</CalendarPrimitive.Header>

View file

@ -1,19 +0,0 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from "bits-ui";
import { cn } from "$lib/utils/ui.js";
type $$Props = CalendarPrimitive.HeadingProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<CalendarPrimitive.Heading
let:headingValue
class={cn("text-sm font-medium", className)}
{...$$restProps}
>
<slot {headingValue}>
{headingValue}
</slot>
</CalendarPrimitive.Heading>

View file

@ -1,16 +0,0 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<div
class={cn("mt-4 flex flex-col space-y-4 sm:flex-row sm:space-x-4 sm:space-y-0", className)}
{...$$restProps}
>
<slot />
</div>

View file

@ -1,27 +0,0 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from "bits-ui";
import ChevronRight from "lucide-svelte/icons/chevron-right";
import { buttonVariants } from "$lib/components/ui/button/index.js";
import { cn } from "$lib/utils/ui.js";
type $$Props = CalendarPrimitive.NextButtonProps;
type $$Events = CalendarPrimitive.NextButtonEvents;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<CalendarPrimitive.NextButton
on:click
class={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
className
)}
{...$$restProps}
let:builder
>
<slot {builder}>
<ChevronRight class="h-4 w-4" />
</slot>
</CalendarPrimitive.NextButton>

View file

@ -1,27 +0,0 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from "bits-ui";
import ChevronLeft from "lucide-svelte/icons/chevron-left";
import { buttonVariants } from "$lib/components/ui/button/index.js";
import { cn } from "$lib/utils/ui.js";
type $$Props = CalendarPrimitive.PrevButtonProps;
type $$Events = CalendarPrimitive.PrevButtonEvents;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<CalendarPrimitive.PrevButton
on:click
class={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
className
)}
{...$$restProps}
let:builder
>
<slot {builder}>
<ChevronLeft class="h-4 w-4" />
</slot>
</CalendarPrimitive.PrevButton>

View file

@ -1,59 +0,0 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from "bits-ui";
import * as Calendar from "./index.js";
import { cn } from "$lib/utils/ui.js";
type $$Props = CalendarPrimitive.Props;
type $$Events = CalendarPrimitive.Events;
export let value: $$Props["value"] = undefined;
export let placeholder: $$Props["placeholder"] = undefined;
export let weekdayFormat: $$Props["weekdayFormat"] = "short";
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<CalendarPrimitive.Root
bind:value
bind:placeholder
{weekdayFormat}
class={cn("p-3", className)}
{...$$restProps}
on:keydown
let:months
let:weekdays
>
<Calendar.Header>
<Calendar.PrevButton />
<Calendar.Heading />
<Calendar.NextButton />
</Calendar.Header>
<Calendar.Months>
{#each months as month}
<Calendar.Grid>
<Calendar.GridHead>
<Calendar.GridRow class="flex">
{#each weekdays as weekday}
<Calendar.HeadCell>
{weekday.slice(0, 2)}
</Calendar.HeadCell>
{/each}
</Calendar.GridRow>
</Calendar.GridHead>
<Calendar.GridBody>
{#each month.weeks as weekDates}
<Calendar.GridRow class="mt-2 w-full">
{#each weekDates as date}
<Calendar.Cell {date}>
<Calendar.Day {date} month={month.value} />
</Calendar.Cell>
{/each}
</Calendar.GridRow>
{/each}
</Calendar.GridBody>
</Calendar.Grid>
{/each}
</Calendar.Months>
</CalendarPrimitive.Root>

View file

@ -1,30 +0,0 @@
import Root from "./calendar.svelte";
import Cell from "./calendar-cell.svelte";
import Day from "./calendar-day.svelte";
import Grid from "./calendar-grid.svelte";
import Header from "./calendar-header.svelte";
import Months from "./calendar-months.svelte";
import GridRow from "./calendar-grid-row.svelte";
import Heading from "./calendar-heading.svelte";
import GridBody from "./calendar-grid-body.svelte";
import GridHead from "./calendar-grid-head.svelte";
import HeadCell from "./calendar-head-cell.svelte";
import NextButton from "./calendar-next-button.svelte";
import PrevButton from "./calendar-prev-button.svelte";
export {
Day,
Cell,
Grid,
Header,
Months,
GridRow,
Heading,
GridBody,
GridHead,
HeadCell,
NextButton,
PrevButton,
//
Root as Calendar,
};

View file

@ -1,13 +1,16 @@
<script lang="ts"> <script lang="ts">
import type { WithElementRef } from "bits-ui";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js"; import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLDivElement>; let {
ref = $bindable(null),
let className: $$Props["class"] = undefined; class: className,
export { className as class }; children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div class={cn("p-6 pt-0", className)} {...$$restProps}> <div bind:this={ref} class={cn("p-6", className)} {...restProps}>
<slot /> {@render children?.()}
</div> </div>

View file

@ -1,13 +1,16 @@
<script lang="ts"> <script lang="ts">
import type { WithElementRef } from "bits-ui";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js"; import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLParagraphElement>; let {
ref = $bindable(null),
let className: $$Props["class"] = undefined; class: className,
export { className as class }; children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLParagraphElement>> = $props();
</script> </script>
<p class={cn("text-sm text-muted-foreground", className)} {...$$restProps}> <p bind:this={ref} class={cn("text-muted-foreground text-sm", className)} {...restProps}>
<slot /> {@render children?.()}
</p> </p>

View file

@ -1,13 +1,16 @@
<script lang="ts"> <script lang="ts">
import type { WithElementRef } from "bits-ui";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js"; import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLDivElement>; let {
ref = $bindable(null),
let className: $$Props["class"] = undefined; class: className,
export { className as class }; children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div class={cn("flex items-center p-6 pt-0", className)} {...$$restProps}> <div bind:this={ref} class={cn("flex items-center p-6 pt-0", className)} {...restProps}>
<slot /> {@render children?.()}
</div> </div>

View file

@ -1,13 +1,16 @@
<script lang="ts"> <script lang="ts">
import type { WithElementRef } from "bits-ui";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js"; import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLDivElement>; let {
ref = $bindable(null),
let className: $$Props["class"] = undefined; class: className,
export { className as class }; children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div class={cn("flex flex-col space-y-1.5 p-6", className)} {...$$restProps}> <div bind:this={ref} class={cn("flex flex-col space-y-1.5 p-6 pb-0", className)} {...restProps}>
<slot /> {@render children?.()}
</div> </div>

View file

@ -1,21 +1,25 @@
<script lang="ts"> <script lang="ts">
import type { WithElementRef } from "bits-ui";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import type { HeadingLevel } from "./index.js"; import { cn } from "$lib/utils.js";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLAttributes<HTMLHeadingElement> & { let {
tag?: HeadingLevel; ref = $bindable(null),
}; class: className,
level = 3,
let className: $$Props["class"] = undefined; children,
export let tag: $$Props["tag"] = "h3"; ...restProps
export { className as class }; }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
level?: 1 | 2 | 3 | 4 | 5 | 6;
} = $props();
</script> </script>
<svelte:element <div
this={tag} role="heading"
class={cn("text-lg font-semibold leading-none tracking-tight", className)} aria-level={level}
{...$$restProps} bind:this={ref}
class={cn("text-2xl font-semibold leading-none tracking-tight", className)}
{...restProps}
> >
<slot /> {@render children?.()}
</svelte:element> </div>

View file

@ -1,16 +1,20 @@
<script lang="ts"> <script lang="ts">
import type { WithElementRef } from "bits-ui";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils/ui.js"; import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLDivElement>; let {
ref = $bindable(null),
let className: $$Props["class"] = undefined; class: className,
export { className as class }; children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
class={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)} bind:this={ref}
{...$$restProps} class={cn("bg-card text-card-foreground rounded-lg border shadow-sm", className)}
{...restProps}
> >
<slot /> {@render children?.()}
</div> </div>

View file

@ -20,5 +20,3 @@ export {
Header as CardHeader, Header as CardHeader,
Title as CardTitle, Title as CardTitle,
}; };
export type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";

View file

@ -1,35 +0,0 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import emblaCarouselSvelte from "embla-carousel-svelte";
import { getEmblaContext } from "./context.js";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: string | undefined | null = undefined;
export { className as class };
const { orientation, options, plugins, onInit } = getEmblaContext("<Carousel.Content/>");
</script>
<div
class="overflow-hidden"
use:emblaCarouselSvelte={{
options: {
container: "[data-embla-container]",
slides: "[data-embla-slide]",
...$options,
axis: $orientation === "horizontal" ? "x" : "y",
},
plugins: $plugins,
}}
on:emblaInit={onInit}
>
<div
class={cn("flex", $orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col", className)}
data-embla-container=""
{...$$restProps}
>
<slot />
</div>
</div>

View file

@ -1,25 +0,0 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { getEmblaContext } from "./context.js";
import { cn } from "$lib/utils/ui.js";
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: string | undefined | null = undefined;
export { className as class };
const { orientation } = getEmblaContext("<Carousel.Item/>");
</script>
<div
role="group"
aria-roledescription="slide"
class={cn(
"min-w-0 shrink-0 grow-0 basis-full",
$orientation === "horizontal" ? "pl-4" : "pt-4",
className
)}
data-embla-slide=""
{...$$restProps}
>
<slot />
</div>

View file

@ -1,39 +0,0 @@
<script lang="ts">
import ArrowRight from "lucide-svelte/icons/arrow-right";
import type { VariantProps } from "tailwind-variants";
import { getEmblaContext } from "./context.js";
import { cn } from "$lib/utils/ui.js";
import {
Button,
type Props,
type buttonVariants,
} from "$lib/components/ui/button/index.js";
type $$Props = Props;
let className: $$Props["class"] = undefined;
export { className as class };
export let variant: VariantProps<typeof buttonVariants>["variant"] = "outline";
export let size: VariantProps<typeof buttonVariants>["size"] = "icon";
const { orientation, canScrollNext, scrollNext, handleKeyDown } =
getEmblaContext("<Carousel.Next/>");
</script>
<Button
{variant}
{size}
class={cn(
"absolute h-8 w-8 touch-manipulation rounded-full",
$orientation === "horizontal"
? "-right-12 top-1/2 -translate-y-1/2"
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
className
)}
disabled={!$canScrollNext}
on:click={scrollNext}
on:keydown={handleKeyDown}
{...$$restProps}
>
<ArrowRight class="h-4 w-4" />
<span class="sr-only">Next slide</span>
</Button>

View file

@ -1,40 +0,0 @@
<script lang="ts">
import ArrowLeft from "lucide-svelte/icons/arrow-left";
import type { VariantProps } from "tailwind-variants";
import { getEmblaContext } from "./context.js";
import { cn } from "$lib/utils/ui.js";
import {
Button,
type Props,
type buttonVariants,
} from "$lib/components/ui/button/index.js";
type $$Props = Props;
let className: $$Props["class"] = undefined;
export { className as class };
export let variant: VariantProps<typeof buttonVariants>["variant"] = "outline";
export let size: VariantProps<typeof buttonVariants>["size"] = "icon";
const { orientation, canScrollPrev, scrollPrev, handleKeyDown } =
getEmblaContext("<Carousel.Previous/>");
</script>
<Button
{variant}
{size}
class={cn(
"absolute h-8 w-8 touch-manipulation rounded-full",
$orientation === "horizontal"
? "-left-12 top-1/2 -translate-y-1/2"
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
className
)}
disabled={!$canScrollPrev}
on:click={scrollPrev}
on:keydown={handleKeyDown}
{...$$restProps}
>
<ArrowLeft class="h-4 w-4" />
<span class="sr-only">Previous slide</span>
</Button>

View file

@ -1,98 +0,0 @@
<script lang="ts">
import { writable } from "svelte/store";
import { onDestroy } from "svelte";
import { type CarouselAPI, type CarouselProps, setEmblaContext } from "./context.js";
import { cn } from "$lib/utils/ui.js";
type $$Props = CarouselProps;
export let opts = {};
export let plugins: NonNullable<$$Props["plugins"]> = [];
export let api: $$Props["api"] = undefined;
export let orientation: NonNullable<$$Props["orientation"]> = "horizontal";
let className: $$Props["class"] = undefined;
export { className as class };
const apiStore = writable<CarouselAPI | undefined>(undefined);
const orientationStore = writable(orientation);
const canScrollPrev = writable(false);
const canScrollNext = writable(false);
const optionsStore = writable(opts);
const pluginStore = writable(plugins);
const scrollSnapsStore = writable<number[]>([]);
const selectedIndexStore = writable(0);
$: orientationStore.set(orientation);
$: pluginStore.set(plugins);
$: optionsStore.set(opts);
function scrollPrev() {
api?.scrollPrev();
}
function scrollNext() {
api?.scrollNext();
}
function scrollTo(index: number, jump?: boolean) {
api?.scrollTo(index, jump);
}
function onSelect(api: CarouselAPI) {
if (!api) return;
canScrollPrev.set(api.canScrollPrev());
canScrollNext.set(api.canScrollNext());
}
$: if (api) {
onSelect(api);
api.on("select", onSelect);
api.on("reInit", onSelect);
}
function handleKeyDown(e: KeyboardEvent) {
if (e.key === "ArrowLeft") {
e.preventDefault();
scrollPrev();
} else if (e.key === "ArrowRight") {
e.preventDefault();
scrollNext();
}
}
setEmblaContext({
api: apiStore,
scrollPrev,
scrollNext,
orientation: orientationStore,
canScrollNext,
canScrollPrev,
handleKeyDown,
options: optionsStore,
plugins: pluginStore,
onInit,
scrollSnaps: scrollSnapsStore,
selectedIndex: selectedIndexStore,
scrollTo,
});
function onInit(event: CustomEvent<CarouselAPI>) {
api = event.detail;
apiStore.set(api);
scrollSnapsStore.set(api.scrollSnapList());
}
onDestroy(() => {
api?.off("select", onSelect);
});
</script>
<div
class={cn("relative", className)}
on:mouseenter
on:mouseleave
role="region"
aria-roledescription="carousel"
{...$$restProps}
>
<slot />
</div>

View file

@ -1,56 +0,0 @@
import type { EmblaCarouselSvelteType } from "embla-carousel-svelte";
import type emblaCarouselSvelte from "embla-carousel-svelte";
import { getContext, hasContext, setContext } from "svelte";
import type { HTMLAttributes } from "svelte/elements";
import type { Readable, Writable } from "svelte/store";
export type CarouselAPI =
NonNullable<NonNullable<EmblaCarouselSvelteType["$$_attributes"]>["on:emblaInit"]> extends (
evt: CustomEvent<infer CarouselAPI>
) => void
? CarouselAPI
: never;
type EmblaCarouselConfig = NonNullable<Parameters<typeof emblaCarouselSvelte>[1]>;
export type CarouselOptions = EmblaCarouselConfig["options"];
export type CarouselPlugins = EmblaCarouselConfig["plugins"];
////
export type CarouselProps = {
opts?: CarouselOptions;
plugins?: CarouselPlugins;
api?: CarouselAPI;
orientation?: "horizontal" | "vertical";
} & HTMLAttributes<HTMLDivElement>;
const EMBLA_CAROUSEL_CONTEXT = Symbol("EMBLA_CAROUSEL_CONTEXT");
type EmblaContext = {
api: Writable<CarouselAPI | undefined>;
orientation: Writable<"horizontal" | "vertical">;
scrollNext: () => void;
scrollPrev: () => void;
canScrollNext: Readable<boolean>;
canScrollPrev: Readable<boolean>;
handleKeyDown: (e: KeyboardEvent) => void;
options: Writable<CarouselOptions>;
plugins: Writable<CarouselPlugins>;
onInit: (e: CustomEvent<CarouselAPI>) => void;
scrollTo: (index: number, jump?: boolean) => void;
scrollSnaps: Readable<number[]>;
selectedIndex: Readable<number>;
};
export function setEmblaContext(config: EmblaContext): EmblaContext {
setContext(EMBLA_CAROUSEL_CONTEXT, config);
return config;
}
export function getEmblaContext(name = "This component") {
if (!hasContext(EMBLA_CAROUSEL_CONTEXT)) {
throw new Error(`${name} must be used within a <Carousel.Root> component`);
}
return getContext<ReturnType<typeof setEmblaContext>>(EMBLA_CAROUSEL_CONTEXT);
}

View file

@ -1,5 +0,0 @@
export { default as Root } from "./carousel.svelte";
export { default as Content } from "./carousel-content.svelte";
export { default as Item } from "./carousel-item.svelte";
export { default as Previous } from "./carousel-previous.svelte";
export { default as Next } from "./carousel-next.svelte";

View file

@ -1,35 +0,0 @@
<script lang="ts">
import { Checkbox as CheckboxPrimitive } from "bits-ui";
import Check from "lucide-svelte/icons/check";
import Minus from "lucide-svelte/icons/minus";
import { cn } from "$lib/utils/ui.js";
type $$Props = CheckboxPrimitive.Props;
type $$Events = CheckboxPrimitive.Events;
let className: $$Props["class"] = undefined;
export let checked: $$Props["checked"] = false;
export { className as class };
</script>
<CheckboxPrimitive.Root
class={cn(
"peer box-content h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[disabled=true]:cursor-not-allowed data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[disabled=true]:opacity-50",
className
)}
bind:checked
{...$$restProps}
on:click
>
<CheckboxPrimitive.Indicator
class={cn("flex h-4 w-4 items-center justify-center text-current")}
let:isChecked
let:isIndeterminate
>
{#if isChecked}
<Check class="h-3.5 w-3.5" />
{:else if isIndeterminate}
<Minus class="h-3.5 w-3.5" />
{/if}
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>

View file

@ -1,6 +0,0 @@
import Root from "./checkbox.svelte";
export {
Root,
//
Root as Checkbox,
};

Some files were not shown because too many files have changed in this diff Show more