예정된 헤더 변경 – 테마 및 플러그인 준비

최근에 Discourse 헤더를 레거시 ‘위젯’ 렌더링 시스템에서 최신 Glimmer 컴포넌트로 업데이트하는 작업을 진행해 왔습니다. 이 변경 사항은 이제 glimmer header mode 사이트 설정을 통해 Discourse 코어에서 사용할 수 있습니다.

:timer_clock: 대략적인 타임라인

(매우 대략적인 추정치이며, 양방향으로 변경될 수 있음)

2024년 1분기:

  • :white_check_mark: 코어 구현 완료 및 Meta에서 활성화

  • :white_check_mark: 업그레이드 가이드 게시; 콘솔 비추천(deprecation) 메시지 활성화

  • :white_check_mark: 모든 공식 및 제3자 플러그인/테마 업데이트 작업 시작

2024년 2분기:

  • :white_check_mark: 새 헤더 구현을 기본적으로 활성화하기 시작

  • :white_check_mark: 공식 및 제3자 테마/플러그인 업그레이드 준비 완료

  • :white_check_mark: 남은 이슈에 대해 관리자 경고 배너가 트리거되는 비추천 메시지 시작

2024년 3분기:

  • :white_check_mark: 더 넓은 가시성을 위한 공지 토픽 게시: Preparing your community for behind-the-scenes header changes

  • :white_check_mark: 2024년 8월 5일 주 (v3.4.0.beta1): 모든 사이트에서 기본적으로 새 헤더 활성화. 관리자는 ‘glimmer header mode’ 사이트 설정을 전환하여 이전 헤더로 되돌릴 수 있습니다.

  • :white_check_mark: 2024년 9월 2일 주: 기능 플래그 및 레거시 코드 최종 제거

:eyes: 나에게 어떤 의미가 있는가?

플러그인이나 테마가 헤더를 커스터마이징하기 위해 ‘위젯’ API를 사용한다면, 새 헤더와의 호환성을 위해 업데이트가 필요합니다.

:person_tipping_hand: 새 헤더를 어떻게 사용해 볼 수 있는가?

최신 버전의 Discourse에서는 모든 테마/플러그인이 호환되는 경우 새 헤더가 자동으로 활성화됩니다.

테마/플러그인이 호환되지 않는 경우, 레거시 헤더가 계속 사용되며 기존 비추천 메시지와 함께 콘솔에 경고가 출력됩니다. 또한 UI에서 관리자에게 경고 배너가 표시됩니다.

이 자동 시스템이 예상대로 작동하지 않는 극히 드문 경우, glimmer header mode 사이트 설정을 통해 이 '자동 기능 플래그’를 일시적으로 오버라이드할 수 있습니다. 그렇게 할 경우, 이 토픽에서 이유를 알려 주시기 바랍니다.

:technologist: 플러그인/테마를 업데이트해야 하는가?

커스터마이징이 업데이트가 필요한지 확인하려면, 다음 위젯 중 하나에 대해 decorateWidget, changeWidgetSetting, reopenWidget 또는 attachWidgetAction을 사용하는지 확인하십시오:

  • header
  • site-header
  • header-contents
  • header-buttons
  • user-status-bubble
  • sidebar-toggle
  • header-icons
  • header-topic-info
  • header-notifications
  • home-logo
  • user-dropdown

또는 다음 플러그인 API 메서드 중 하나를 사용하는지 확인하십시오:

  • addToHeaderIcons
  • addHeaderPanel

이 모든 것들은 이제 콘솔에 비추천 메시지가 출력되도록 합니다. 비추천 ID는 다음과 같습니다:

  • discourse.add-header-panel
  • discourse.header-widget-overrides

:warning: 인스턴스에서 테마를 하나 이상 사용하는 경우, 모든 테마를 확인하십시오.

관리자 공지

2024년 6월 20일부터, 위 비추천 항목에 대한 관리자 공지를 활성화했습니다.

이 날짜 이후에 배포된 인스턴스에서 현재 플러그인, 테마 또는 테마 컴포넌트가 비추천 경고 중 하나를 트리거하는 경우, 다음 메시지는 관리자*에게만 표시됩니다:

이 메시지는 관리자가 영향받는 커스터마이징을 현대화하기 위해 조치가 필요함을 알리기 위한 것입니다: 레거시 코드베이스를 제거할 때까지 이전 커스터마이징은 계속 작동합니다.

:twisted_rightwards_arrows: 대체 방안은 무엇인가?

각 테마/플러그인은 다르지만, 가장 일반적인 사용 사례에 대한 지침은 다음과 같습니다:

addToHeaderIcons

:information_source: 사용자 정의 헤더 아이콘의 경우, 코드를 제거하고 공식 Custom Header Links (Icons) Theme Component를 설치하는 것을 권장합니다. 요구 사항을 충족하지 못하는 경우, 필요한 코드 변경 사항에 대한 세부 정보를 확인하려면 아래를 참조하십시오:

addToHeaderIcons 플러그인 API는 새로운 headerIcons API를 لصالح으로 비추천되었습니다. 이는 헤더에서 아이콘을 추가, 제거 또는 순서를 변경하는 것을 허용하기 위해 존재합니다. 컴포넌트를 전달해야 합니다.

컴포넌트는 다음과 같이 전달할 수 있습니다:

이전 이후
api.addToHeaderIcons(“widget-foo”) api.headerIcons.add(“foo”, FooIcon)
api.decorateWidget(“header-icons:before”, () => return helper.h(“div”, “widget-foo”)) api.headerIcons.add(“foo”, FooIcon, { before: “search” })
api.decorateWidget(“header-icons:after”, () => return helper.h(“div”, “widget-foo”)) api.headerIcons.add(“foo”, FooComponent, { after: “search” })

이 예제는 Ember의 Template Tag Format (gjs)를 사용하여 컴포넌트를 인라인으로 정의하고 headerButtons.add API에 전달합니다:

// .../discourse/api-initializers/add-my-button.gjs

import DButton from "discourse/components/d-button";
import { apiInitializer } from "discourse/lib/api";

export default apiInitializer("1.0", (api) => {
  api.headerIcons.add("some-unique-name", <template>
    <li><DButton class="icon btn-flat" @href="/u" @icon="address-book" /></li>
  </template>);
});

또는 드롭다운의 경우, <DButton 대신 <DMenu를 사용할 수 있습니다:

import DButton from "discourse/components/d-button";
import { apiInitializer } from "discourse/lib/api";
import DMenu from "float-kit/components/d-menu";

export default apiInitializer("1.0", (api) => {
  api.headerIcons.add("some-unique-name", <template>
    <li>
      <DMenu class="icon btn-flat" @icon="address-book">
        <DButton @translatedLabel="User 1" @href="/u/user1" />
        <DButton @translatedLabel="User 2" @href="/u/user2" />
        <DButton @translatedLabel="User 3" @href="/u/user3" />
      </DMenu>
    </li>
  </template>);
});

업그레이드 커밋 예제:

decorateWidget("header-buttons:*")

:information_source: 사용자 정의 헤더 링크의 경우, 코드를 제거하고 공식 Custom Header Links Theme Component를 설치하는 것을 권장합니다. 요구 사항을 충족하지 못하는 경우, 필요한 코드 변경 사항에 대한 세부 정보를 확인하려면 아래를 참조하십시오:

header-buttons 위젯은 비추천되었으며, headerButtons 플러그인 API를 도입했습니다. 이는 헤더에서 버튼을 추가, 제거 또는 순서를 변경하는 것을 허용하기 위해 존재합니다. 컴포넌트를 전달해야 합니다.

이전 이후
api.decorateWidget(“header-buttons:before”) api.headerButtons(“button-name”, ButtonComponent, { before: “auth” })
api.decorateWidget(“header-buttons:after”) api.headerButtons(“button-name”, ButtonComponent, { after: “auth” })

헤더 위젯에 대한 changeWidgetSetting(...)

:information_source: changeWidgetSetting의 가장 일반적인 사용은 다음 테마 컴포넌트를 사용하여 달성할 수 있습니다:

이 경우 사용 사례에 맞지 않는다면, 계속 읽어보세요…

헤더 위젯의 일부 커스터마이징은 changeWidgetSetting API를 사용했습니다.

위와 같은 커스터마이징에 대한 직접적인 대체 방안은 없지만, Glimmer 컴포넌트 필드의 작동 방식 때문에 Discourse 3.3.0.beta3에서 이러한 일부 사례를 처리하기 위해 새로운 플러그인 API를 도입했습니다.

registerValueTransformer는 소스 코드에서 오버라이드 가능하도록 태그된 값을 오버라이드하는 데 사용할 수 있으며, 이는 플러그인 아웃렛이 작동하는 방식과 유사한 접근 방식입니다.

소스 코드 베이스에서 공통적으로 발견된 사용 사례에 대해 두 가지 변환기를 이미 추가했습니다:

  • home-logo-href: 홈 로고 앵커의 URL을 오버라이드하는 데 사용할 수 있습니다. 예제는 아래 home-logo 섹션을 참조하십시오.

  • header-notifications-avatar-size: 헤더의 사용자 아바타에 가져온 이미지의 크기를 변경하는 데 사용할 수 있습니다. 예제:

아래의 코드:

api.changeWidgetSetting(
  "header-notifications",
  "avatarSize",
  settings.header_avatars_size
);

다음과 같이 변환됩니다:

api.registerValueTransformer(
  "header-notifications-avatar-size",
  () => settings.header_avatars_size
);

이러한 변환기는 Discourse 소스 코드에 추가되어야 합니다. 다른 것이 필요한 경우, 아래에 사용 사례를 게시하여 알려 주시기 바랍니다.

새로운 값 변환기 API에 대한 자세한 내용은 여기에서 찾을 수 있습니다.

home-logo

home-logo:before 또는 home-logo:after 위젯 장식의 대체로 home-logo 플러그인 아웃렛을 도입했습니다. 커넥터 파일에서 자동 __before 및 __after 명명을 사용하여 사용자 정의 콘텐츠를 배치할 위치를 지정할 수 있습니다.

before/after 커넥터 파일 명명에 대한 자세한 내용은 여기에서 찾을 수 있습니다.

이전 이후
api.decorateWidget(“home-logo:before”) 콘텐츠를 /connectors/home-logo__before로 이동
api.decorateWidget(“header-buttons:after”) 콘텐츠를 /connectors/home-logo__after)로 이동

home-logo 앵커 URL 변경:

매우 일반적인 요구 사항은 home-logo가 링크하는 URL을 변경하는 것입니다. 이를 해결하기 위해 home-logo-href 값 변환기를 도입했습니다. 예제:

  • 정적 URL로 링크를 변경하려면

    api.registerValueTransformer("home-logo-href", () => "https://example.com");
    
  • 현재 사용자를 기반으로 동적 URL을 반환하려면

    api.registerValueTransformer("home-logo-href", () => {
      const currentUser = api.getCurrentUser();
      return `https://example.com/${currentUser.username}`;
    });
    
  • 테마-컴포넌트 설정을 기반으로 URL을 반환하려면

    api.registerValueTransformer("home-logo-href", () => {
      return settings.example_logo_url_setting;
    });
    

:sos: 다른 커스터마이징은 어떻게 되는가?

커스터마이징을 CSS, PluginOutlets 또는 우리가 도입한 새로운 API를 사용하여 달성할 수 없는 경우, 논의하기 위해 새로운 Development 토픽을 만들어 알려 주시기 바랍니다.

:sparkles: 새와 구 헤더를 모두 지원하도록 테마/플러그인을 어떻게 업데이트하는가?

이 문서에 나열된 모든 새로운 API와 플러그인 아웃렛은 새 헤더와 구 헤더 모두에서 지원됩니다. 따라서 현재 테마/플러그인에 한 번만 업데이트하면 사용자는 전환에 대비할 수 있습니다.

그렇다면 FooIcon은 어떻게 정의하나요?

플러그인에서 /assets/javascripts/discourse/components/server-link.js를 생성해 보았습니다(다른 hbs 파일에서 사용하는 컴포넌트들처럼요).

import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";

export default Component.extend({
// 여기에 무언가를 넣어야 하나요?
});

그리고 assets/javascripts/discourse/templates/components/server-link.hbs에는
this is a link를 넣었습니다(이 "Hello, world"가 작동하게 되면 링크로 만들 수 있을 것 같습니다).

위 예제에는 const IconWithDropdown = ...가 있는데, 이걸 어디에 두어야 하나요? 초기화자(initializer)에 넣어보았지만(api.decorateWidget이 있던 곳), 제 판단으로는 유효한 JavaScript나 Ember 코드로 보이지 않습니다.

이전에는 headerlinks 배열이 있었고, 다음과 같이

        headerLinks.push(
          h(
            `li.headerLink.no-servers`,
            h("a", anchorAttributes, I18n.t("pfaffmanager.no_servers_title"))
          )
        );

원하는 링크를 추가했습니다. 다음 코드가 작동하게 된다면, 그 배열을 만들던 루프 안에 그냥 넣으면 될 것 같습니다.

      api.headerIcons.add("foo", ServerLink, { before: "search" });

아니, 진짜. 그래서 glimmer 컴포넌트는 assets/javascripts/discourse/component에, ember 컴포넌트는 assets/javascripts/discourse/components에 들어가는 거야?!?

이제 server-link.gjs 파일이 생겼는데,

import Component from "@ember/component";
export default class ServerLink extends Component {
  // URL을 위한 필수 인자
  url = null;
  // 링크 텍스트를 위한 선택 인자
  text = 'asdf';
  click() {
    console.log('ServerLink clicked!',this);

  }
  // 컴포넌트 템플릿
  <template>
    {{log "my template" this}}
    LINK!
    <a href={{this.url}}>{{this.text}}</a>
  </template>
}

그리고 초기화 프로그램(initializer)에서는 이렇게 하고 있어:

      api.headerIcons.add("foo", ServerLink, { param: "url, yo", before: "search" });

이제 헤더에 무언가가 표시는 돼.

근데 ServerLink에 데이터를 어떻게 전달하는 거야? 다른 URL과 다른 클릭 텍스트로 여러 번 호출해야 해. 컴포넌트에서 그 {} 안의 내용을 어떻게 봐야 하는지 도통 모르겠어.

그리고 <template> 전에 자바스크립트를 넣으면 안 돼. 내 console.log("")가 파싱되지 않으니까!

또 이렇게 시도도 해봤어:

      const x = new ServerLink({
        url: "mylink",
        text: "my-text",
        name: 'Bob',
        message: 'Generated from JavaScript',
      });

그리고 ServerLink 대신 x를 전달했지만, 여전히 안 돼.

헤더에 아이콘/텍스트/URL이 다른 여러 버튼을 원하는 건가요, 아니면 같은 버튼이지만 컨텍스트에 따라 텍스트/URL이 바뀌는 걸 원하는 건가요?

네, 클래스 안에 있습니다—거기서 변수, 함수 또는 템플릿을 선언하세요!

네. 링크가 사용자별로 달라집니다. 기존 코드는 servers 배열을 통해 링크를 가져와서 이 배열에 push했습니다:

            headerLinks.push(
              h(
                `li.headerLink${deviceClass}${newClass}`,
                h("a", anchorAttributes, linkText)
              )
            );

그리고 이렇게 처리했습니다:

      // api.decorateWidget("header-buttons:before", (helper) => {
      //   return helper.h("ul.pfaffmanager-header-links", headerLinks);
      // });

이렇게 하면 헤더에 최대 3개의 링크가 추가되고, 각각은 별도의 서버 URL로 연결되었습니다.

아하. 이제 이해했습니다.

아니, 걱정 마 - 컨벤션은 여전히 /components/야 :sweat_smile:

(기술적으로는 gjs 컴포넌트를 원하는 대로 정의하고 전달할 수 있어서, 디렉터리 이름을 마음대로 정할 수 있어. 하지만 우리는 /components/를 따르고 있어.)

응, 좋은 질문이야 - 헤더에 아이콘을 추가하는 방법에 대해 ‘from scratch’ 문서를 작성해서 더 나은 참고 자료를 제공하도록 노력할게.

그동안 참고할 만한 the discourse-icon-header-links 업데이트를 살펴보는 것도 좋아. GJS를 사용하는 멋진 점은 컴포넌트를 어디서든 정의할 수 있고, 로컬 스코프의 변수에 접근할 수 있다는 거야.

즉, 초기화 파일 이름을 .gjs로 변경하면 다음과 같은 작업을 수행할 수 있어

servers.forEach((server) => {
  api.headerIcons.add(`server-${server.id}`, <template>
    <li><DButton @translatedLabel={{server.name}} @icon="server" /></li>
  </template>);
});

또는 같은 파일 내에서 더 위에 컴포넌트를 정의한 뒤 이렇게 사용할 수도 있어

class ServerButton extends Component {
  get icon(){
    // 아이콘을 결정하는 로직
  }
  <template>
    <li><DButton @translatedLabel={{@server.name}} @icon={{this.icon}} /></li>
  </template>
}

...

servers.forEach((server) => {
  api.headerIcons.add(`server-${server.id}`, <template>
    <ServerButton @server={{server}} />
  </template>);
});

또는 반복문을 템플릿 안으로 옮길 수도 있어 (서버 목록이 런타임에 변경될 수 있는 TrackedArray인 경우 유용해!)

api.headerIcons.add("server-buttons", <template>  
  {{#each servers as |server|}}
    <ServerButton @server={{server}} />
  {{/each}}
</template>);

아. 다행이다. components에서 시도해 봤는데 안 되었던 것 같아서.

감사합니다! 이 중 하나를 작동시킬 수 있을 것 같습니다. 헤더 링크에 대한 링크가 큰 도움이 되었습니다. 제가 코드를 작성할 때 그 컴포넌트를 직접 살펴보고 파악할 만큼의 판단력은 있었을 것 같습니다.

희망의 빛이 보이기 시작합니다!

@david 님과 @Arkshine 님! 해냈어요!

뭐라고요? 그냥 이름을 바꾸면 된다는 거요? 이건 좀 황당하네요. 하지만 정말로 해보니, 이제

          servers.filter(Boolean).map((server) => {
            const linkHref = `/pfaffmanager/servers/${server.id}`;
            const linkTitle = `click to configure server ${server.id}`;
            let host = String(server.hostname);
            const linkText = host.replace(
              /www.|community.|forums?.|talk.|discourse./,
              ""
            );
            const serverLink = <template>
              <li class="headerLink">
                <a class="btn-flat" href={{linkHref}} title={{linkTitle}}>
                  {{host}}
                </a>
              </li>
            </template>;
            const beforeIcon = ["chat", "search", "hamburger", "user-menu"];
            api.headerIcons.add(host, serverLink, { before: beforeIcon });
          });

이전과 동일한 방식으로 동작하고 있어요! 제가 원했던 바로 그 결과입니다!

네, 그건 정말 멋져 보이네요. 제 바람을 더 잘 충족시켜 주는 방법이기도 하고요. 하지만 해당 항목들이 그렇게 자주 바뀌지는 않으니, 오늘은 여기까지로 하겠습니다. 호스트명이 변경되면 링크가 변경되도록 페이지를 새로고침해야 하니까요.

위 내용을 업데이트하실 때 여기 있는 제 불필요한 내용들은 삭제해 주실 거라고 생각해요(문서화 주제에서 이렇게 수다를 떨지 않았어야 했는데…).

OP를 완전한 gjs 예제 몇 개로 업데이트했고, upstream Ember 문서에 대한 링크도 포함했습니다. @pfaffman, 어떠신가요? 추가로 넣을 가치가 있는 다른 게 있을까요?

동작하는 예제가 있어서 더 좋습니다. 그런데 Ember 컴포넌트와 Glimmer 컴포넌트가 따로 있다는 게 맞나요? 맞다면, Glimmer 컴포넌트가 필요하다고 언급해야 할 것 같습니다.

그리고 Glimmer가 어떻게 작동하는지에 대한 Glimmer 문서 링크를 달아주면 어떨까요?

예제처럼 인라인 컴포넌트를 사용할 수 있고, 같은 파일에서 변수에 할당하는 방식이나, components 디렉토리에 있는 다른 파일에 넣어 포함하는 방식도 있는 것 같습니다. 이 주제에서는 너무 많은 내용일 수 있지만, 이 주제에 대해 별도의 전용 게시물을 만들어주면 좋겠습니다.

완전히 호환 가능합니다. Classic Ember 컴포넌트든 Glimmer 컴포넌트든 사용할 수 있습니다. 그리고 이 두 가지 중 어느 것을 사용하든, 기존 스타일의 .js/.hbs 형식이나 새로운 스타일의 .gjs 형식으로 작성할 수 있습니다.

Ember 문서에 대한 링크를 몇 개 포함해 볼게요 :+1:

:mega: 오늘 이 변경 사항을 병합했습니다. 이를 통해 호환되는 테마/플러그인을 사용하는 사이트에서 새로운 헤더 구현이 자동으로 활성화됩니다.

테마/플러그인이 호환되지 않는 경우, 기존 헤더가 계속 사용되며 기존 비추천(deprecation) 메시지와 함께 콘솔에 경고가 출력됩니다. 가까운 시일 내에 이 콘솔 경고는 UI 내 경고 배너로 업그레이드될 예정입니다.

이 자동 변경 사항으로 인해 문제가 발생하는 경우(가능성이 낮지만), glimmer header mode 사이트 설정을 통해 이 '자동 기능 플래그’를 일시적으로 오버라이드할 수 있습니다. 그렇게 할 경우, 이 주제에서 그 이유를 알려주시기 바랍니다.

나는 변경 사항을 만들려는 것이 아니었지만, 비공고(notice)들이 말해주는 바는 다릅니다.

즉, 선택지가 있고, 현 상태를 유지하는 쉬운 방법이 있을까요?

또는

신규 헤더를 사용해 보고 구버전 헤더를 유지하기로 선택할 경우 무엇을 놓치게 될까요? 신규 헤더가 무엇을 의미하는지 이해하지 못하겠습니다. 그룹 설정은 보았고, 다양한 그룹에 대한 맞춤 설정은 흥미롭지만, 무엇이 커스터마이즈될 수 있나요?

오늘 이것을 발견했습니다.

저는 이러한 변경 사항에 대해 고수나 마법사가 아닙니다. 시간이 걸리기도 하고, 여기서 사용자들이 쉽게 이해하거나 아는 것처럼 기술을 배우고 싶을 정도로 자주 하지 않습니다.

솔직히 처음부터 이걸 해야 한다는 것이 조금 불만입니다. 하지만 푸딩을 다 써 버린 노인처럼 소리를 지르기 전에, 이것이 어디로 향하는지, 왜, 그리고 어떻게 되는지 알고 싶습니다.

저는 이것을 직업으로 하고 있지만, 이 자바스크립트 관련 일들은 여전히 쉽지 않다고 느껴요.

저도 노인이고, 당신의 고통을 잘 이해합니다.

아쉬운 일이지만, 그저 기술의 발전일 뿐이에요. 이 에임버(Ember) 업그레이드가 많은 부분을 망가뜨렸고, 아직 끝나지 않았거든요.

그 커스터마이징을 했을 때 이미 "당신이 원한 것"이었어요. 지난 5년 동안 새 폰이나 랩톱을 사셨을 거라고 확신합니다.

내가 당신이라면 (그리고 당신이 나와 비슷하게, 풀타임 디스코스(Discourse) 운영 직함이 없는 상태라면), Marketplace 채널에 게시글을 올릴 거예요. 내가 나라면 300달러 미만의 제안에는 응답하지 않을 가능성이 높지만, 다른 누군가가 100달러나 200달러에 도와줄 합리적인 가능성이 있습니다. 아마도 5년 이상은 다시 깨지지 않을 거라고 추측해요.

햄버거 메뉴의 테마 선택기는 제거하고 사이드바를 사용하는 것이 좋을 것 같습니다.

정직하고 좋은 답변 감사합니다. 다만 활용할 수 있는 내용은 많지 않네요. 더 많은 내용이 나올 수 있겠죠 (그랬으면 좋겠습니다).

여기서 자바를 다루고 있다는 사실조차 몰랐습니다 :man_shrugging:

누군가 당신의 '푸딩(소유물/이익)'을 가져가길 원하지 않죠 :face_with_hand_over_mouth:

물론이죠, 하지만 목표는 무엇일까요? 이 소프트웨어는 너무 많은 영역을 다루고 있어서 누가 어떤 끝을 보고 있는지 궁금합니다.

이것은 단순히 에임버(Ember) 업그레이드 때문에 필요한 것일까요?

에임버를 도입한 이유도 모르겠지만, 작동하는 것이라면 왜 고치려 하는지 의문입니다. 모든 것이 미래로 이어진다는 긴 설명이 있겠죠, 하지만 공유할 수 있는 진정한 비전은 없을까요?

저는 매우 오래된 소프트웨어를 사용하는 다른 포럼들도 방문합니다. 개인적으로 discourse는 그 어떤 포럼보다 훨씬 낫다고 보지만, 비교하자면 그들은 큰 어려움을 겪는 것 같지 않습니다. 성장 문제는 비슷하고, 대부분은 소프트웨어보다 사람의 문제라고 생각합니다. 자신의 '푸딩’을 잃어버린 고참들이 너무 많거든요. 저는 궁금합니다. 그 모든 포럼들을 완전히 무용지물로 만들 IOT(사물인터넷)의 미래가 정말로 올까요? discourse는 그 사실을 알고 대비하고 있을까요?

당신이 제공하는 그 정직함이 더 있네요 :grin: 맞습니다. 당시 저는 배우고자 하는 열망이 더 컸고, 더 야심 차았으며, 그 가치가 더 있다고 느꼈습니다. 그 이후로 많은 고초를 겪고 짓밟혀 죽은 듯이 방치되었죠.

좋습니다, 그 베팅을 받아들입니다. 이미 지신 상태이니까 이 문제 해결에 도와주세요. 그러면 우리는 친구가 될 수 있죠.

오래전에 그만뒀을 겁니다. '짓밟혀 죽은 듯이 방치되었다’는 표현은 다소 관용적인 표현이었죠. 사실은 저 혼자 운전대를 잡고 있는 상태입니다. 다른 누군가는 어딘가의 패널에서 하이퍼드라이브를 고치려 하고 있겠죠. 저는 다른 사람들과 자주 소통하지 않아서 잘 모르지만, 우리는 자금 지원이 없습니다. 저희(FULL30)는 소셜 미디어와 discourse에서도 플랫폼에서 추방(de-platformed)되었거든요. discourse가 자발적으로 관계를 끊은 다른 유료 고객들이 얼마나 될지, 혹은 그들의 신념이 너무 공격적이라서 discourse가 공개적으로 돈을 써서 그들을 반대하는 경우가 얼마나 될지 궁금합니다.

그럼에도 불구하고 저는 진실을 말하지만 모욕으로 받아들이지 않습니다. 살고 살게 하듯 살아가는 것이죠. 미래가 올 것임을 압니다. 다만 제가 왜 여전히 여기 있고, 여전히 시도하고 있는지 모르겠습니다. 하지만 저는 여전히 여기 있고, 시도하고 있습니다. 그래서 계속 시도할 것입니다. AA(알코올 중독자 익명 모임)처럼, 오늘 하루만이라도 :hugs:

하지만 제가 그것을 도입했을 때는 모든 사람들이 그렇게 하던 때였어요 :expressionless:

사이드바(여기서)는 햄버거 메뉴로 닫을 수 있고, 기능적으로 큰 차이는 없습니다. 내비게이션 창을 열었다 닫는 것이니까요. 하지만 제 것은 쉽게 저장할 수 없나요?

네, 제 커스터마이징된 코드를 정리하고 깔끔하게 작동하게 해줄 누군가에게 돈을 지불하고 싶습니다. 기꺼이 지불할 의향이 있습니다. 저는 다른 사람들을 고용하는 것을 즐기고, 부를 공유하는 것을 좋아합니다. 커리어를 쌓으면 자선가가 되고 싶습니다. 하지만 오늘은 자선가가 필요합니다 :innocent: 그리고 다시 한번 다른 사람들이 제공할 수 있는 모든 도움에 감사드립니다.

다른 방법은 커뮤니티에 도움을 요청하는 것입니다. 커스터마이징을 중단하고, 코드를 공유하는 새 주제를 만들어 도움을 구하세요. 최근 저는 이런 식으로 많은 도움을 받았습니다.

불행히도 아닙니다. '구 헤더’를 계속 사용할 수 있는 기능은 과도기적인 조치일 뿐입니다. 곧 새 헤더가 유일한 옵션이 될 것입니다.

네! Development 채널에서 질문이 들어오면 항상 기꺼이 도와드립니다. 또한 코도와 해결책을 공개적으로 공유하면 다른 사람들에게 유용한 자료가 됩니다.

후, 내 커뮤니티는 다른 이슈들에 더 민감하네요.

물론 여기서 공유할 수는 있지만, 그러면 방향이 반대가 되죠. 우리를 도와줄 관심을 가질 코더는 누가 있을까요?

아이러니하게도, 코딩은 미래의 화기가 될 수 있으며, 훨씬 더 많은 죽음과 파괴를 초래할 수도 있겠네요. (이건 좀 벗어난 이야기이긴 합니다)

알겠습니다. 그렇다면 제게 정확히 어떤 의미가 되나요? 하나의 사용자 그룹을 생성하고, 공개되며 로그인하지 않은 상태로 두는 것인가요?

이 그룹 설정들은 신뢰 수준에 기반한 것인지, 아니면 사냥 그룹이나 낚시 그룹 같은 실제 서로 다른 그룹에 기반한 것인지 파악이 잘 안 됩니다.

우선 목표를 이해해야 하고, 나홀로 활동하는 저의 노력이 시간 절약과 내 포럼의 고유한 느낌을 유지하는 데 가장 큰 효과를 발휘할 수 있는 곳이 어디인지 파악해야 합니다.


누군가의 스레드를 어긋나게 하고 싶지 않습니다. 이 내용이 별도의 스레드로 분리되어야 한다고 판단된다면 저는 괜찮습니다.

사람들이 마음에 들지 않는 것을 삭제해야 한다는 필요성을 느끼는 상황에서, 진정한 일체감 있는 관계는 어떻게 형성될 수 있을까요?

타인을 이해하는 것은 인내심이 필요합니다. 삭제된 링크는 게시 중에는 보이지 않았지만 나중에 로고가 누락된 것으로 나타났습니다. 또 다른 헤더 이슈를 논의해야 하나요?

그것은 제 포럼에 80대 중반인 남성이라고 믿는 사람이 작성한 게시물입니다. 확실히 물어볼 수는 있지만, 그는 저와 대화하기를 거부합니다. 그를 꾸짖거나, 밴하거나, 외면해야 하나요?

아니요, 왜냐하면 더 나은 방법이 있기 때문입니다. 하지만 그것은 타인과 그들의 생각을 받아들이는 것을 의미합니다. 저는 나쁜 지역에서 좋은 사람들을, 나빠 보이는 좋은 사람들을, 그리고 그 반대인 경우들을 모두 발견합니다.

맞습니다. 방금 오류들을 발견했고, 해결하고 싶지만 미래가 변하고 있다는 점을 제외하고는 근본 원인을 이해하지 못합니다. 새로운 헤더가 필요하다고요, 좋습니다. 제 사이트를 설정할 올바른 방향은 무엇인가요? 단순한 튜닝일까요, 아니면 전면적인 방향 전환일까요?

우리는 이 세 영역만 작업하면 된다는 것에 대해 논의하고 있는 건가요?

저는 컴포넌트 사용이 혼합되어 있습니다. 처음에는 사용하지 않다가 나중에 유용할 수 있다는 것을 알게 되었습니다. 저는 완전한 컴포넌트 사용을 하지 않았고, 혼합된 상태를 유지하고 있습니다.

컴포넌트 없이 제 테마를 참고용으로 올립니다.
discourse-full30-ii.zip (10.1 KB)
일부, 특히 모달은 최근부터 이미 작동하지 않고 있습니다. 그것들도 올릴 수 있습니다.