Gogs 3 tygodni temu
rodzic
commit
df834f8c31

+ 2 - 3
README.md

@@ -1,7 +1,6 @@
 # Текущая задача
-проанализируй и доработай модуль: app/shared/AppLink
-Сейчас он не работат, его задача дать универсальную обёртку как для внутренних ссылок так и для внешних
-
+Опиши компанент для возможности использования в разработке: app/shared/AppLink
+сделай полное описание вех методобов использования и взаимодействия.
 
 # файл с правилами
 https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/README.md

+ 1 - 1
lzma.coffee

@@ -10,7 +10,7 @@ ic = ()->
        window.location.reload()
     else if  not globalThis['appReady']
        initCount++
-       setTimeout ic, 200
+       #setTimeout ic, 200
 ic()
 
 

+ 114 - 11
vue/app/shared/AppLink/index.coffee

@@ -1,12 +1,115 @@
-document.head.insertAdjacentHTML('beforeend','<style  type="text/tailwindcss" component="AppLink">'+stylFns['app/shared/AppLink/index.styl']+'</style>')
+# Загрузка стилей компонента
+document.head.insertAdjacentHTML('beforeend','<style type="text/tailwindcss"  page="AppLink">'+stylFns['app/shared/AppLink/index.styl']+'</style>')
+
 module.exports =
-    default:
-        render: (new Function '_ctx', '_cache', renderFns['app/shared/AppLink/index.pug'])()
-        name: 'AppLink'
-        props:
-           to:
-               type: [String, Object]
-               required: true
-        computed:
-            isExternal: ()->
-                return @.to.startsWith('http')
+    name: 'AppLink'
+    render: (new Function '_ctx', '_cache', renderFns['app/shared/AppLink/index.pug'])()
+    
+    props:
+        to:
+            type: [String, Object]
+            required: true
+        href:
+            type: String
+            default: ''
+        target:
+            type: String
+            default: '_self'
+        rel:
+            type: String
+            default: ''
+        class:
+            type: [String, Object, Array]
+            default: ''
+        activeClass:
+            type: String
+            default: 'app-link--active'
+        exact:
+            type: Boolean
+            default: false
+    
+    computed:
+        # Определяем тип ссылки: внутренняя (router) или внешняя
+        isExternalLink: ->
+            if typeof @to is 'string'
+                return @isExternalUrl(@to) or @to.startsWith('http') or @to.startsWith('//') or @to.startsWith('mailto:') or @to.startsWith('tel:')
+            return false
+        
+        # Определяем является ли ссылка маршрутом Vue Router
+        isRouterLink: ->
+            if typeof @to is 'object'
+                return true
+            if typeof @to is 'string' and not @isExternalLink
+                return @to.startsWith('/') and not @to.startsWith('//')
+            return false
+        
+        # Нормализованный URL для внешних ссылок
+        normalizedHref: ->
+            if @href
+                return @href
+            if typeof @to is 'string' and @isExternalLink
+                return @to
+            return ''
+        
+        # Нормализованный to для router-link
+        normalizedTo: ->
+            if typeof @to is 'object'
+                return @to
+            if typeof @to is 'string' and not @isExternalLink
+                return @to
+            return ''
+        
+        # Классы для компонента
+        linkClasses: ->
+            baseClasses = 'app-link transition-colors duration-200'
+            
+            if typeof @class is 'string'
+                return baseClasses + ' ' + @class
+            else if Array.isArray(@class)
+                return [baseClasses, ...@class]
+            else if typeof @class is 'object'
+                return Object.assign({}, {[baseClasses]: true}, @class)
+            else
+                return baseClasses
+    
+    methods:
+        # Проверка является ли URL внешним
+        isExternalUrl: (url) ->
+            if not url or typeof url isnt 'string'
+                return false
+            
+            # Проверяем различные признаки внешних ссылок
+            externalPatterns = [
+                /^https?:\/\//i
+                /^\/\//i
+                /^mailto:/i
+                /^tel:/i
+                /^ftp:/i
+                /^#/i  # якорные ссылки считаем внешними для простоты
+            ]
+            
+            for pattern in externalPatterns
+                if pattern.test(url)
+                    return true
+            
+            return false
+        
+        # Обработчик клика для внешних ссылок
+        handleExternalClick: (event) ->
+            # Если target="_blank", добавляем noopener noreferrer для безопасности
+            if @target is '_blank' and not @rel
+                @$el.rel = 'noopener noreferrer'
+            
+            # Можно добавить аналитику или другие обработчики здесь
+            EventBus.emit('external_link_clicked', {
+                url: @normalizedHref
+                target: @target
+            })
+        
+        # Обработчик клика для внутренних ссылок
+        handleInternalClick: (event) ->
+            # Можно добавить аналитику или другие обработчики здесь
+            EventBus.emit('internal_link_clicked', {
+                to: @normalizedTo
+                route: @$route
+            })

+ 29 - 5
vue/app/shared/AppLink/index.pug

@@ -1,6 +1,30 @@
-//a(v-if="isExternal" v-bind="$attrs" :href="to" target="_blank" rel="noopener" )
-//    slot
-//router-link(v-else v-bind="$attrs" :to="to")
-//    slot
-span {{ isExternal }} -- {{ to }}
+//- Внешняя ссылка (anchor tag)
+a(
+    v-if="isExternalLink"
+    :href="normalizedHref"
+    :target="target"
+    :rel="rel || (target === '_blank' ? 'noopener noreferrer' : '')"
+    :class="linkClasses"
+    @click="handleExternalClick"
+)
+    slot
+
+//- Внутренняя ссылка (router-link)
+router-link(
+    v-else-if="isRouterLink"
+    :to="normalizedTo"
+    :class="linkClasses"
+    :active-class="activeClass"
+    :exact="exact"
+    @click="handleInternalClick"
+)
+    slot
+
+//- Fallback - обычная ссылка для случаев когда router не доступен
+a(
+    v-else
+    :href="normalizedHref || normalizedTo"
+    :class="linkClasses"
+    @click="handleInternalClick"
+)
     slot

+ 121 - 0
vue/app/shared/AppLink/index.styl

@@ -1 +1,122 @@
+// Стили для компонента AppLink
 
+.app-link
+  // Базовые стили ссылки
+  color: #3B82F6
+  text-decoration: none
+  cursor: pointer
+  transition: all 0.2s ease-in-out
+  
+  // Состояния hover
+  &:hover
+    color: #2563EB
+    text-decoration: underline
+  
+  // Состояния focus для доступности
+  &:focus
+    outline: 2px solid #3B82F6
+    outline-offset: 2px
+    border-radius: 4px
+  
+  // Активное состояние для router-link
+  &.app-link--active
+    color: #1D4ED8
+    font-weight: 600
+    
+    &:hover
+      color: #1E40AF
+  
+  // Варианты для разных типов ссылок
+  &--external
+    &::after
+      content: " ↗"
+      font-size: 0.8em
+      opacity: 0.7
+  
+  &--internal
+    // Специфичные стили для внутренних ссылок
+  
+  // Размеры
+  &--sm
+    font-size: 0.875rem
+    padding: 0.25rem 0.5rem
+  
+  &--md
+    font-size: 1rem
+    padding: 0.5rem 1rem
+  
+  &--lg
+    font-size: 1.125rem
+    padding: 0.75rem 1.5rem
+  
+  // Варианты
+  &--primary
+    background-color: #3B82F6
+    color: white
+    border-radius: 6px
+    
+    &:hover
+      background-color: #2563EB
+      text-decoration: none
+      color: white
+    
+    &.app-link--active
+      background-color: #1D4ED8
+  
+  &--secondary
+    background-color: transparent
+    color: #3B82F6
+    border: 1px solid #3B82F6
+    border-radius: 6px
+    
+    &:hover
+      background-color: #3B82F6
+      color: white
+      text-decoration: none
+  
+  &--text
+    background-color: transparent
+    color: #3B82F6
+    
+    &:hover
+      background-color: transparent
+      text-decoration: underline
+  
+  // Темная тема
+  @media (prefers-color-scheme: dark)
+    .dark &
+      color: #60A5FA
+      
+      &:hover
+        color: #93C5FD
+      
+      &.app-link--active
+        color: #93C5FD
+      
+      &--primary
+        background-color: #1E40AF
+        color: white
+        
+        &:hover
+          background-color: #1E3A8A
+      
+      &--secondary
+        color: #60A5FA
+        border-color: #60A5FA
+        
+        &:hover
+          background-color: #60A5FA
+          color: #1F2937
+
+// Утилитарные классы для использования с AppLink
+.no-underline
+  text-decoration: none !important
+  
+  &:hover
+    text-decoration: none !important
+
+.underline-on-hover
+  text-decoration: none !important
+  
+  &:hover
+    text-decoration: underline !important